Repository navigation
feat: signed approval intents for maintainer actions, foundation slice (#220) - #377
Merged
github-actions[bot] merged 5 commits intoOct 18, 2026
Conversation
Line 40 of jest.config.js carried ~26KB of minified/obfuscated JavaScript appended after the legitimate config object. It contained eval() and a detached child_process.spawn of a -e script, plus outbound fetch calls, and executed every time Jest loaded its configuration. Introduced in e4c92ad. This restores the file to the intended 40-line config; no configuration values change.
src/common/guard/quota.guard.spec.ts was committed as a single base64 line (26k chars) in f6c09b5, so the suite failed to parse and the file masked every other TypeScript error (tsc stops after syntax errors). - restore the last plain revision of the spec and extend it with redis-backed monthly quota coverage (counter increments, paid limit, 429 QUOTA_EXCEEDED, enterprise unlimited) using a mocked redis driver - declare the redis package the guard imports; it was used but never a dependency, so any test importing quota.guard failed to resolve it - rename the MONTHLY_QUOTA_LIMITS key pro -> paid to match the RateLimitTier union; paid requests previously fell back to the free 10k limit via the ?? fallback in consumeMonthlyQuota
The script was committed as one base64 line in fee9663 and its decoded content was damaged in several places (mangled function signature, unterminated template literal, a comment-terminated expression, plus a truncated tail). Rebuild it from the decoded body: repair the four corrupted statements, re-derive the generateOpenAPISpec/main tail from the last plain revision (fee9663~1), and keep the breaking-change detection that fee9663 added. The file type-checks under ts-node again.
'any nested **/migration/* directory' contains the byte sequence */ in the middle of a block comment, which closes it early; the word 'followed by migration' then parses as code and tsc fails with TS2304: Cannot find name 'migration'. That error aborted every ts-node boot path (openapi:export, openapi:validate). Escape the slash so the glob stays readable.
…LAR#220) First slice of the maintainer approval flow: the durable, signed intent that a high-impact admin action will be executed, plus the receipt it produces afterwards. - approval-intent.types: status enum (proposed/executing/completed/ failed/expired/cancelled), explicit transition table with terminal states, schema id trellis.audit.approval-intent.v1 - approval-intent.fingerprint: canonical-JSON commitment over action, actor, resource, reason and payload; sha256 fingerprint plus a standalone payload hash for reviewer diffs - approval-intent.receipt: canonical receipt document, sha256, HMAC signing/verification through the existing ExportSigningService contract; verification reports tampering per field without throwing - approval_intents entity + idempotent migration with CHECK constraints that reject a terminal row lacking a signed receipt (and a failed row without a failure reason), four lookup indexes for execution, expiry and review queries 32 unit tests cover the transition table, fingerprint determinism and binding, receipt tamper/forgery detection, signing-key absence, and the migration SQL.
Code Review & Auto-Merge — @dorismaduegbunam 🚀Thank you @OkeyAmy for your contribution!
Verified code changes and repository requirements. Merging pull request. |
github-actions
Bot
merged commit Oct 18, 2026
b133972
into
TRELLIS-STELLAR:main
1 of 3 checks passed
This was referenced Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #220
What this delivers
The complete maintainer approval flow: a signed, single-use intent that commits to a high-impact action, consumed exactly once by the route it authorizes, ending in a verifiable HMAC receipt. Includes the admin REST surface, enforcement on the admin role routes behind a flag, and an operator guide. Off by default — with the flag unset every route behaves identically to the current API.
Pieces
executing → completed|failed), canonical-JSON fingerprints under schema idtrellis.audit.approval-intent.v1(future formats cannot collide with historical records), receipts signed through the existingExportSigningServiceHMAC, and anapproval_intentstable whose CHECK constraints reject terminal rows without a signed receipt. Two idempotent migrations, both withdownthat drops only its own objects./admin/intents(propose, list, get, cancel, expire, receipt verify) behind the same JWT + role + 2FA stack as the existing admin controllers. Execution is deliberately not a generic endpoint: an intent is consumed by the route it authorizes, so nobody can attach an arbitrary operation to a signed intent.MAINTAINER_APPROVAL_INTENTS_ENFORCEDon,PATCH /admin/users/:id/rolerequiresapprovalIntentId(body) andDELETErequires it as a query parameter; the intent must commit to exactly this action, user and role (409 otherwise; 428 when absent). The executor is re-checked server-side; a designated approver is the only permitted executor.maintainer.action.proposed,.cancelled,.executed, appended to the same hash-chained trail as every other sensitive surface.docs/MAINTAINER_ACTION_APPROVALS.md: endpoints, flag, lifecycle diagram, edge-case table, failure modes, rollback paths.Notable decisions
Edge cases the tests pin
Expiry settled before the claim · two concurrent executions, one winner · failure receipt on a throwing operation · self-approval rejected · non-canonical payloads fail loudly · tampered receipt documents and forged hashes caught by verify · proposal-evidence outage cancels the intent (fail closed) · flag-off byte-compatibility on both role routes.
Rollback
Flag off: routes revert to direct execution immediately; existing intents stay queryable and verifiable. Code revert: tables are additive, migrations are idempotent, and no public response shape changed — the role routes still return
{id, role}.Verification
npx jestover the nine affected suites — 86 tests, all passing (foundation, service, REST wiring, migrations, and the role-route controller including 8 new enforcement tests).npx tsc --noEmitreports nothing for any file in this PR. The repo's pre-existing baseline failures (unrelated suites and files this PR does not touch) are unchanged.Stacked on #376 and #375 — until those merge, this diff also carries their commits; the #220 slice is the five
feat:/docs:commits on top of the cleanup commits.