{"_id":"@coderifts/gateway-verifier","_rev":"3-cc511c411a1c9600186489cb2b78bec4","name":"@coderifts/gateway-verifier","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@coderifts/gateway-verifier","version":"0.1.0","license":"MIT","_id":"@coderifts/gateway-verifier@0.1.0","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/gateway-verifier#readme","bugs":{"url":"https://github.com/coderifts/gateway-verifier/issues"},"dist":{"shasum":"25136845c308b97069ac326117f76c949f97395f","tarball":"https://registry.npmjs.org/@coderifts/gateway-verifier/-/gateway-verifier-0.1.0.tgz","fileCount":11,"integrity":"sha512-h9gwWun7SMmvPlxJaJ6A3mFtFlgn64989XAta5lpwFiKa3zBG3y2Br8j5tnySy7525ljOVUIxgh0xvoR5QTapQ==","signatures":[{"sig":"MEYCIQDVr/yavIITCYg6yvHsTbacF24+hBi5YEU7GC9eYkYw2wIhAJDT5hkxkgC2Iad8BFqC/RrLqE8Y1GttnvKL/fE0Pivk","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83842},"main":"src/index.js","engines":{"node":">=18"},"gitHead":"e406622c7e8b62d8b1ac12ff67fe916fb60d703c","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"repository":{"url":"git+https://github.com/coderifts/gateway-verifier.git","type":"git"},"_npmVersion":"11.6.2","description":"Reject an API request unless it carries a CodeRifts receipt that verifies and whose scope matches the request. Customer-hosted, offline, zero dependencies.","directories":{},"_nodeVersion":"24.12.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gateway-verifier_0.1.0_1789799096942_0.40441387298040476","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@coderifts/gateway-verifier","version":"0.1.1","license":"MIT","_id":"@coderifts/gateway-verifier@0.1.1","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"homepage":"https://github.com/coderifts/gateway-verifier#readme","bugs":{"url":"https://github.com/coderifts/gateway-verifier/issues"},"dist":{"shasum":"66d6c80564128745ec6bc5d068af1db0793325a3","tarball":"https://registry.npmjs.org/@coderifts/gateway-verifier/-/gateway-verifier-0.1.1.tgz","fileCount":11,"integrity":"sha512-O04lqvrT1Pre4/BVDAGgTcCibbGxgeGplDKps7qcnI6IEyVyUG95N/cpLeIA9ULAX9xdNwR1b46q5W78osZIYg==","signatures":[{"sig":"MEUCIQCNkAVZ3qGmd6VfmIattesWFiwTSaoGrmbDVRxneDuL2wIgAigFd2hzwVNOYBJbdXMcpGH/uW+VjmYbndQWd2RbArY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIDV512Q6nGC1HwVyRalZE2Qp2nVick6G6ttZhqPgc4AJAiEAugLbX8wKTmqg2C3ezNg1cUoXiPXrsR10H3a3E6gEG7k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84506},"main":"src/index.js","engines":{"node":">=18"},"gitHead":"ffd03fa83f7fe337740ff46062ab0b17f88213b6","scripts":{"test":"node --test test/*.test.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"repository":{"url":"git+https://github.com/coderifts/gateway-verifier.git","type":"git"},"_npmVersion":"11.6.2","description":"Reject a request unless a CodeRifts receipt verifies and matches its scope. Only a granted change can proceed.","directories":{},"_nodeVersion":"24.12.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gateway-verifier_0.1.1_1789910371715_0.6302006588316043","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"_id":"@coderifts/gateway-verifier@0.1.2","bugs":{"url":"https://github.com/coderifts/gateway-verifier/issues"},"dist":{"shasum":"75e4a8f9280489ece651b90dbf55e32d1f6f9dba","tarball":"https://registry.npmjs.org/@coderifts/gateway-verifier/-/gateway-verifier-0.1.2.tgz","fileCount":11,"integrity":"sha512-yCWF00yWTcY7PhnHjNCQnI3gPZ1FnOJ78niEP7M8ypTUpoHJ3S4VrpC61781xRwo1/fNhKRxP/EcSiqE5cm6bg==","signatures":[{"sig":"MEQCIETXKhNAJXHNDUcvzX3k9HCYoEbRNowIZ5kccbaL67DDAiBvYAizvyGBcl1h6ImbdWkDCJJVoKa/kxpjoL/f9VZ+1A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEPeaALafjgIHgFy8pHoyCvKEKAmop21v57dMB68oBapAiAnczRxgsGivjQtig+wu86ZvJRDn6MDwGenCIHq8/oAJQ=="}],"unpackedSize":90533},"main":"src/index.js","name":"@coderifts/gateway-verifier","engines":{"node":">=18"},"gitHead":"4ac8952595f3df39812069359c90ce2cbc7de92f","license":"MIT","scripts":{"test":"node --test test/*.test.js"},"version":"0.1.2","_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"homepage":"https://github.com/coderifts/gateway-verifier#readme","repository":{"url":"git+https://github.com/coderifts/gateway-verifier.git","type":"git"},"_npmVersion":"11.6.2","description":"Reject a request unless a CodeRifts receipt verifies and matches its scope. Only a granted change can proceed.","directories":{},"maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"_nodeVersion":"24.12.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gateway-verifier_0.1.2_1790019033617_0.8871366445176092"}}},"time":{"created":"2026-09-19T06:24:56.791Z","modified":"2026-09-21T19:30:33.890Z","0.1.0":"2026-09-19T06:24:57.094Z","0.1.1":"2026-09-20T13:19:31.796Z","0.1.2":"2026-09-21T19:30:33.703Z"},"bugs":{"url":"https://github.com/coderifts/gateway-verifier/issues"},"license":"MIT","homepage":"https://github.com/coderifts/gateway-verifier#readme","repository":{"url":"git+https://github.com/coderifts/gateway-verifier.git","type":"git"},"description":"Reject a request unless a CodeRifts receipt verifies and matches its scope. Only a granted change can proceed.","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"readme":"# CodeRifts gateway verifier\n\nSigned, offline-verifiable authorization for AI-agent contract changes. Only a\ngranted change can proceed.\n\nReject an API request unless it carries a CodeRifts receipt that **verifies** and\nwhose **scope matches the request**.\n\nRuns in your gateway. Offline, zero dependencies, keyring pinned by you.\n\n---\n\n## What this is\n\nA **target verifier**. It checks evidence the caller already holds, then forwards\nor refuses.\n\n## What this proves / does not prove\n\n**Proves:** the receipt token is authentic under the **caller-pinned** keyring,\nunexpired for the configured clock, and the resolved intent (operation + target)\nmatches the receipt scope.\n\n**Does not prove:** that the change was preflighted correctly; that\n`execution_action` was CONTINUE; that artifacts still match; that the upstream\npolicy is right; that the keyring is fresh. A missing or unmapped route is\nrefused, not waved through.\n\nIt is **not** an analysis service. Nothing here asks whether a request is risky —\nthat question is answered upstream, before the caller reaches you, and its answer\nis the receipt this checks.\n\n`publishConfig.access` is `\"public\"`. Whether to run `npm publish --access public`\nis Péter's decision. `@coderifts/gateway-verifier@0.1.0` is already on the npm\nregistry (measured 2026-09-20).\n\n## Install\n\nCopy `src/` into your gateway image, or `npm install` it from your own registry.\nThere are no dependencies and nothing to fetch at runtime.\n\n## Use\n\n```js\nconst { gatewayVerifier } = require('@coderifts/gateway-verifier');\n\napp.use(gatewayVerifier({\n  // kid -> { publicKey, status, retired_at }. YOU pin this.\n  keyring: myKeyring,\n\n  // What does this request mean in YOUR domain? Return the decision-envelope\n  // fields that must match. Returning null refuses the request.\n  resolveIntent: (req) => {\n    const m = /^\\/v1\\/orders\\/([^/]+)\\/refund$/.exec(req.path);\n    if (req.method === 'POST' && m) {\n      return { operation: 'refund', target_uri: `order:${m[1]}` };\n    }\n    return null;          // an unmapped route is refused, not waved through\n  },\n}));\n```\n\nHeaders the caller sends:\n\n| header | contents |\n| --- | --- |\n| `X-CodeRifts-Receipt` | the compact receipt, or a DSSE/in-toto envelope |\n| `X-CodeRifts-Decision` | the decision envelope, base64 JSON |\n\nAn `ext-authz`-style standalone check is in `src/ext-authz.js` for gateways that\ncall an external authorization service rather than running middleware.\n\n## What it checks, in order\n\n1. the receipt header is present;\n2. a DSSE envelope is unwrapped to its compact token (**nothing is verified\n   while unwrapping** — the signature is over the compact bytes and is checked\n   next);\n3. the decision envelope parses;\n4. **the receipt verifies** against your keyring, including the body-hash binding\n   to that exact decision envelope;\n5. the `execution_action` is one that permits proceeding;\n6. **the scope matches** what your `resolveIntent` says this request is doing.\n\nAny step can refuse. Refusals are named:\n\n`receipt_missing` · `decision_missing` · `decision_malformed` ·\n`dsse_malformed` · `dsse_unsupported` · `dsse_predicate_mismatch` ·\n`receipt_invalid` · `decision_not_allow` · `scope_mismatch` ·\n`intent_unresolved` · `verifier_threw`\n\n### The order is load-bearing\n\nThe scope comes from the decision envelope, which the **caller** supplies. On its\nown that would be worthless. It is trustworthy only because step 4 binds the\nreceipt to that exact envelope by body hash: swap the envelope and the receipt\nstops verifying. This never scope-checks before verifying.\n\n### What a 403 body carries\n\n| key | what it is |\n|---|---|\n| `remedy` | **this gateway's** refusal class — the grant is missing, invalid, or scoped elsewhere, and how to obtain one |\n| `next_step` | **the decision's** own `next_agent_step`, verbatim from the `decision_result` envelope |\n\nThe two can co-occur; they answer different questions. `next_step` appears only when\nthe receipt verified: the field lives inside `decision_result`, so `decision_body_hash`\ncovers it and the receipt signs it. The envelope arrives in a request header, so anyone\nwho can reach the gateway can write one — a refusal reached before verification, or one\nwhose envelope was swapped after signing, renders no `next_step`.\n\nThis is the decision's remediation suggestion, not permission; branch on `execution_action`.\n\n## What it proves\n\nFor an admitted request:\n\n* a holder of a key **you pinned** signed a receipt;\n* that receipt is bound to the decision envelope presented with it — not to some\n  other decision;\n* the decision's `execution_action` permits proceeding;\n* the decision's scope matches what you said this request is doing.\n\n## What it does NOT prove\n\n* **That the action described actually happened, or will.** This gate is in front\n  of the request; it does not observe the outcome.\n* **That a monitoring sink is wired.** `CONTINUE_WITH_MONITORING` is admitted on\n  the decision's claim. The result sets `monitoring_claim_unverified: true` —\n  read it rather than assuming that half was checked.\n* **That your route mapping is right.** `resolveIntent` is yours. If it says a\n  destructive route is a read, this admits a receipt for a read. The verifier\n  cannot check a mapping only you know.\n* **That the caller is who they say.** This is authorization evidence, not\n  authentication. Keep your existing authn.\n* **That the key is uncompromised.** Everything reduces to \"a holder of this key\n  signed this\". Custody is yours.\n\n## Customer-hosted\n\nYou run it, in your gateway, against a keyring you pin. There is no call to\nCodeRifts on the request path and no CodeRifts-operated service in the loop —\nverification is a local signature check. If CodeRifts is unreachable, or gone,\nthis keeps working.\n\nThe verify core (`src/verify.js`, `src/arity.js`, `src/from-dsse.js`) is\n**vendored**: copied in, not imported, so the artifact you audit is the artifact\nthat runs. The copied revision and the SHA-256 of each file are recorded in\n[`VENDOR.md`](VENDOR.md) and `src/VENDOR.sha256`; `test/vendor-core.test.js`\nfails if either file drifts from its pin, and separately re-checks the key-status\nbehaviour the pin exists to protect.\n\n## Tests\n\n```bash\nnpm test\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}