test(project-engine-client,user-manager-client): spec-verify checksum gate (LLMO-5976)#1777
test(project-engine-client,user-manager-client): spec-verify checksum gate (LLMO-5976)#1777aliciadriani wants to merge 2 commits into
Conversation
… gate (LLMO-5976) Commit a SHA-256 of each vendored Semrush swagger beside the spec and verify it in test/foundation.test.js (runs in CI via `npm test`). Any re-vendor changes the bytes and fails CI until a human reviews the diff and bumps the recorded hash in the same PR, so silent spec drift is impossible — a re-vendor is inert until the hash is bumped. The vendored specs are untouched (byte-for-byte). Includes gate self-tests (passes on match, fails on a tampered byte). Documents the mechanism in each package CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
This PR will trigger no release when merged. |
There was a problem hiding this comment.
Hey @aliciadriani,
Verdict: Approve - clean, well-scoped checksum gate with no blocking issues.
Complexity: LOW - small diff, single concern, no risk signals.
Changes: Adds SHA-256 checksum verification gates to both vendored Semrush OpenAPI specs, preventing silent re-vendor without human review (6 files).
Note: Recommend a human read before merge - this change modifies package-level CLAUDE.md files (architectural documentation). The bot review is a complement to, not a replacement for, a human read here.
Non-blocking (3): minor issues and suggestions
- nit: No
.gitattributesrule guarantees byte-stable checkouts for the vendored YAML specs. If a contributor hascore.autocrlf=true, the spec could check out with CRLF, producing a hash mismatch that looks like drift but is just a line-ending difference. Considerspec/*.yaml eol=lfin each package or at the repo root. - suggestion: The two test implementations are identical except for file paths. If a third vendored spec adopts this pattern, extract a shared helper (e.g.,
makeChecksumGate(specPath, checksumPath)) to avoid copy-paste drift. - nit: The "detects a byte-for-byte mismatch" test asserts a property of SHA-256 itself (different inputs produce different outputs), not a property of the gate logic. It has documentation value but cannot meaningfully fail unless
createHashis broken.
Note: CI checks are currently pending.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 10s | Cost: $3.16 | Commit: 91266f112758d3805d45dbf60e9b1a3016edc7fc
If this code review was useful, please react with 👍. Otherwise, react with 👎.
Two follow-on lines drifted since the ADR's 2026-07-06 date: - LLMO-5976 (spec-verify gate) shipped via #1811, not #1777 (#1777 is still open). - LLMO-5979 (request timeouts) has since shipped in #1819 (was "in progress / open"). Docs-only; no decision change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#1781) ## Spec LLMO-5975: agree the ownership boundary for the shared Semrush client before the facade build-out (LLMO-5977) lands, so subsequent PRs don't re-litigate it. **Boundary decided:** - Shared client owns transport: IMS Bearer auth, retries/backoff, request timeouts, a typed error taxonomy. - Consumers own: error→HTTP translation, caching, redaction. - Test: is it true for every consumer (→ shared) or specific to one (→ consumer)? **LLMO-5980 disposition:** investigation confirmed transport behavior has already diverged between spacecat-shared's client and spacecat-api-service's hand-built Serenity transport (shared has retry/backoff, api-service has none). That divergence is closed directly via a targeted retry-parity fix in api-service (tracked separately, not gated on this ADR). Migrating api-service onto the shared client itself is recorded as "revisit deliberately" — not funded now, not closed as a non-goal. It's a deliberate future call, sequenced after the facade exists, not something the resilience gap should stampede. ## Implementation plan - Adds `docs/adr/0001-shared-semrush-client-ownership.md` — status Accepted, starts a `docs/adr/` practice in this repo (previously no ADR file/directory existed anywhere in spacecat-shared; tickets were tracked purely via inline external Jira links). - No code changes. Doc-only PR. - Follow-on work referenced in the ADR: LLMO-5977 (facade, gated on this), LLMO-5978+5979 (typed errors + timeouts, one combined hardening PR), LLMO-5980 (deferred), LLMO-5976 (spec-verify CI gate — independent, already shipped in #1777). --------- Co-authored-by: Alicia Adriani <aadriani+adobe@adobe.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Spec
LLMO-5976: any re-vendor of the Semrush OpenAPI spec must force a reviewed hash bump.
The vendored spec stays byte-for-byte; if its actual bytes drift from the committed
digest, CI fails until a human reviews the change and bumps the recorded hash in the
same PR. This closes the gap where a silent re-vendor could slip through unreviewed —
the existing overlay-freshness gate (
test/overlay.test.js) only pins theCRncorrection overlay against generated types, not the raw vendored bytes.
Implementation plan
Existed: both Semrush client packages (
project-engine-client,user-manager-client)already had an overlay-freshness gate pinning corrections against generated types, and
test/foundation.test.jsalready asserted textual facts about the vendored spec(basePath, swagger version) — but neither pinned the spec's raw bytes. That was the gap.
Added (smallest shippable version — extends existing files, no new framework, no
new src/mock logic, zero coverage burden):
packages/spacecat-shared-project-engine-client/spec/projectengine_swagger_public.yaml.sha256— committed digest.
packages/spacecat-shared-user-manager-client/spec/usermanager_swagger.yaml.sha256— committed digest.
describeblock appended to each package'stest/foundation.test.jsthathashes the vendored spec bytes (
Buffer, not utf-8) and asserts equality against thecommitted digest, plus a self-test proving hashing tampered bytes does NOT match.
CLAUDE.mdnext to the "spec is never edited" line.The vendored specs remain byte-for-byte unchanged.
CI integration point: runs as a normal Mocha test under each package's
npm test(
c8 mocha), which the root.github/workflows/main.yamlTest job already invokes onevery PR via the shared
lint-test-coveragecomposite action. No new workflow, no newnpm script — same path as every other unit test.
Verification:
npm test -w packages/spacecat-shared-project-engine-client— 230 passing, 100%stmts/branches/funcs/lines.
npm test -w packages/spacecat-shared-user-manager-client— 167 passing, 100%stmts/branches/funcs/lines.
"vendored spec drifted" message, reverted.
Cut as speculative:
spec:verifynpm script — redundant with the CI-run Mocha test andwould carry its own coverage burden.
types.tsor the overlay — the overlay gate alreadyguards corrections, and
types.tsderives from the spec this gate now pins.module for two call sites.
Note:
/create-prskill was not available in this session; this PR was opened directlyvia
gh pr createwith the body manually structured to match the unified template shape.🤖 Generated with Claude Code