Skip to content

fix(sdl): report every sdl the manifest cannot be built from as invalid input - #4054

Merged
baktun14 merged 1 commit into
mainfrom
fix/sdl-report-unbuildable-sdl-as-invalid
Sep 25, 2026
Merged

baktun14 merged 1 commit into
mainfrom
fix/sdl-report-unbuildable-sdl-as-invalid

Conversation

@baktun14

Copy link
Copy Markdown
Contributor

Why

On 2026-09-24 at 10:56 and 11:03 UTC, POST /v1/deployments answered 500 for an SDL that gave a storage size as a bare byte count, and it paged the 5xx alert. #4033 turned that case into a 400 later that day. It's only one of the ways chain-sdk's manifest generator throws on a document its own validator accepts, and the others still answer 500 on POST and PUT:

  • GPU units that aren't a whole number (1.5, "abc") fail the BigInt conversion with a RangeError or SyntaxError.
  • A deployment entry for a service the SDL never declares throws a TypeError, but only when the manifest groups are first read. That read happened outside fix(sdl): report a memory or storage size without a unit as invalid input #4033's guard, while the manifest version was being hashed. The new functional test reproduces the 500 on main.
  • A placement, signedBy or anyOf given as a plain value crashed the step that adds the allowed auditors, before chain-sdk ever validated the document.

What

  • The generator reads nothing but the document, so anything it throws is now reported as a validation error (400) in the generator's own words. The guard also reads the lazily built groups and reclamation before returning, so a failure there is caught too. A size without a unit keeps the message fix(sdl): report a memory or storage size without a unit as invalid input #4033 gave it.
  • A thrown value that isn't an Error still propagates. So does every failure outside the generator (reference resolvers, the key service, the database, the signer), so those still answer 500.
  • Adding the auditor requirement skips a placement shape it can't write to and leaves it to chain-sdk's validator, whose 400 names the field ("anyOf" at "/profiles/placement/dcloud/signedBy" should be array.).
  • Create, update and patch all build the manifest before they reclaim trial orphans, seal secrets, record the definition, broadcast or push a manifest. The functional tests check that a refused document is never stored or sent.

One tradeoff to weigh in review: a real chain-sdk bug that breaks a valid SDL would now surface as a 400 to the caller instead of paging. The error handler still logs it at error level.

Stryker kills 53 of 54 mutants on the changed lines. The survivor is equivalent: replacing [] in Array.isArray(anyOf ?? []) with another array gives the same result.

…id input

Commit 6903b3b turned chain-sdk's "Invalid size string" throw into a 400, but
that is only one of the ways the manifest generator throws on a document its own
validator accepts. GPU units that are not a whole number fail the BigInt
conversion. A deployment entry for a service the SDL never declares fails only
when the manifest groups are first read, and that read happened outside the
guard, while the manifest version was being hashed. Both still answered 500 on
POST and PUT /v1/deployments, which pages the 5xx alert.

The generator reads nothing but the document, so the guard now reports anything
it throws as a validation error with the generator's own message. It also reads
the lazily built groups and reclamation before leaving the guard. A size without
a unit keeps the message that commit gave it. A thrown value that is not an Error
still propagates, as does every failure outside the generator (reference
resolvers, the key service, the database, the signer), so those still answer 500.

The auditor requirement is written into the placements before chain-sdk
validates the document, and it threw on a placement, signedBy or anyOf that was
not the mapping or list it writes to. It now skips those shapes and leaves them
to the validator, whose 400 names the field.

Create, update and patch all build the manifest before they reclaim trial
orphans, seal secrets, record the definition, create or update the deployment, or
push a manifest, so a refused document is never recorded or sent anywhere.
@baktun14
baktun14 requested a review from a team as a code owner September 25, 2026 14:42
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 8 billable files and costs up to $2.00.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 52 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: akash-network/console/.coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: d88d45e2-ed34-443a-ba01-ab5955a039da

📥 Commits

Reviewing files that changed from the base of the PR and between d8d5f8b and df7e347.

📒 Files selected for processing (8)
  • apps/api/src/deployment/services/deployment-writer/deployment-writer.service.spec.ts
  • apps/api/src/deployment/services/sdl/sdl.service.spec.ts
  • apps/api/src/deployment/services/sdl/sdl.service.ts
  • apps/api/src/deployment/utils/sdl-manifest/sdl-manifest.spec.ts
  • apps/api/src/deployment/utils/sdl-manifest/sdl-manifest.ts
  • apps/api/src/deployment/utils/sdl-sizes/sdl-sizes.spec.ts
  • apps/api/src/deployment/utils/sdl-sizes/sdl-sizes.ts
  • apps/api/test/functional/deployments.spec.ts

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.62%. Comparing base (c441107) to head (df7e347).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4054      +/-   ##
==========================================
- Coverage   87.77%   87.62%   -0.15%     
==========================================
  Files        1282     1177     -105     
  Lines       36138    33422    -2716     
  Branches     8603     8060     -543     
==========================================
- Hits        31720    29286    -2434     
+ Misses       3909     3646     -263     
+ Partials      509      490      -19     
Flag Coverage Δ *Carryforward flag
api 93.52% <100.00%> (+0.04%) ⬆️
deploy-web 81.81% <ø> (ø) Carriedforward from c441107
log-collector ?
notifications 94.28% <ø> (ø) Carriedforward from c441107
provider-console 81.68% <ø> (ø) Carriedforward from c441107
provider-inventory ?
provider-proxy 89.16% <ø> (ø) Carriedforward from c441107
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...pps/api/src/deployment/services/sdl/sdl.service.ts 98.64% <100.00%> (+0.07%) ⬆️
.../src/deployment/utils/sdl-manifest/sdl-manifest.ts 100.00% <100.00%> (ø)

... and 119 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and didn't find any bugs. Because it changes error-handling behavior for every SDL-driven deployment create/update (POST and PUT /v1/deployments) and the author themselves flags a real tradeoff to weigh (a genuine chain-sdk bug on a valid SDL would now surface as a 400 instead of paging), a human look would still be worthwhile.

What was reviewed: the new generateManifestReportingBuildFailures (catches any Error while building/reading groups, groupSpecs, reclamation, maps size errors to the existing size ValidationError and everything else to a generic manifest ValidationError, rethrows non-Error throws); the canTakeAuditors guard replacing the old truthy check in #appendAuditorRequirement; and the unit/functional tests confirming a size-without-unit SDL and an SDL deploying an undeclared service both cleanly 400 with no reclamation/seal/db-write/broadcast side effects, while a non-SDL failure (e.g. secret store unreachable) still propagates as-is.

Extended reasoning...

The diff replaces sdl-sizes.ts with sdl-manifest.ts, broadening a narrow catch (only "Invalid size string") into a catch-all that maps any Error thrown while building or eagerly reading chain-sdk's manifest (groups/groupSpecs/reclamation) into a 400 ValidationError, and adds a canTakeAuditors guard so malformed placement/signedBy/anyOf shapes are deferred to chain-sdk's own validator instead of crashing. It touches no auth/crypto/secrets logic itself but does change how all deployment create/update requests handle manifest-build failures, a central production path; new unit, service and functional tests (including negative-path assertions that no reclamation/seal/db-write/broadcast happens) cover the new behavior well and mirror the CLAUDE.md setup/mock conventions. No findings were raised by the bug hunt, but the PR author explicitly calls out a design tradeoff (masking a real chain-sdk bug as a 400 instead of paging) that is worth a human sign-off given the criticality of the path.

@baktun14
baktun14 added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 54aa9f7 Sep 25, 2026
59 checks passed
@baktun14
baktun14 deleted the fix/sdl-report-unbuildable-sdl-as-invalid branch September 25, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant