Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/CURRENT-STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,27 @@ and its digest remain unchanged. Regression coverage exercises a lost settlement
a later-attempt readback, tampered stored grants and read-only recovery after grant
expiry, with the publication count fixed at one. This remains source validation,
not a real publication or DoneState terminal outcome.


## Workers redirect compatibility repair — 18 October 2026

Protected release canary [39122966755](https://github.com/AyobamiH/agentproof-release-canary/actions/runs/39122966755)
passed authorisation but stopped at preparation with `release_policy_rejected`.
Its publication artifact SHA-256 is
`de151fc8a32090fb6916803de230d37b56a2e99aa2657c3193ad15471f49fdca`.
The existing exact release remained a draft; no reservation or publication evidence
was returned and the verifier job did not run.

A GET-only reproduction using the Workers runtime identified the cause:
`redirect: "error"` is rejected before the GitHub request is sent. Node-only
fixtures had incorrectly required this mode. Both the release provider and separate
receipt signer's metadata reader now use `redirect: "manual"`; their existing
exact HTTP 200 checks continue to refuse redirects. Regression cases cover all
five redirect statuses, zero durable reservation and no redirected follow-up.

This is a source correction awaiting exact-source deployment and live acceptance.
Existing target fences, signing identities, source/OIDC pins and the single-PATCH
policy are unchanged. The independently verified repository-patch run
[39121692291](https://github.com/AyobamiH/agentproof/actions/runs/39121692291)
remains evidence for `d89f6d54709830ff49373ab7c2797c927ced8ac9`.
RC6 npm publication is unchanged; independent-installation credit remains zero.
63 changes: 63 additions & 0 deletions docs/evidence/release-workers-redirect-failure-20261018.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"schema": "agentproof.release-runtime-compatibility-evidence.v1",
"recordedAt": "2026-10-18T11:32:02.594441+00:00",
"baseSource": "d89f6d54709830ff49373ab7c2797c927ced8ac9",
"failedWorkflow": "https://github.com/AyobamiH/agentproof-release-canary/actions/runs/39122966755",
"failedWorkflowCommit": "cc1dfb79c1a63a62e69049473b6170674667d8d1",
"publicationArtifactSha256": "de151fc8a32090fb6916803de230d37b56a2e99aa2657c3193ad15471f49fdca",
"before": {
"at": "2026-10-18T11:28:49.979Z",
"readOnly": true,
"result": {
"error": "release_v1:github_provider_unavailable",
"calls": [
{
"path": "/repos/AyobamiH/agentproof-release-canary",
"failure": "TypeError: Invalid redirect value, must be one of \"follow\" or \"manual\" (\"error\" won't be implemented since it does not make sense at the edge; use \"manual\" and check the response status code)."
}
]
}
},
"after": {
"at": "2026-10-18T11:31:13.740Z",
"readOnly": true,
"result": {
"observation": {
"schema": "agentproof.release.observation.v1",
"ownerId": 47716486,
"repositoryId": 1423718326,
"releaseId": 416342082,
"tagName": "v0.0.0-rc.2026101801",
"tagCommit": "1231076c12485a02fae3c38b0b850a25274985d5",
"packageAssetId": 653036082,
"packageAssetName": "agentproof-disposable-canary.tgz",
"packageDigest": "sha256:064f989c25b86269004401959b1e2aa68cc0b3acbf310ba647b892aa5e28b186",
"provenanceAssetId": 653046879,
"provenanceDigest": "sha256:fa76d7de87ba327ccd81943563af7daed1c87775e049e52a047df59c5b1475b4",
"assetCount": 2,
"draft": true,
"prerelease": true,
"publishedAt": null
},
"calls": [
{
"path": "/repos/AyobamiH/agentproof-release-canary",
"status": 200,
"type": "application/json; charset=utf-8"
},
{
"path": "/repos/AyobamiH/agentproof-release-canary/git/ref/tags/v0.0.0-rc.2026101801",
"status": 200,
"type": "application/json; charset=utf-8"
},
{
"path": "/repos/AyobamiH/agentproof-release-canary/releases/416342082",
"status": 200,
"type": "application/json; charset=utf-8"
}
]
}
},
"scope": "Local Workers-runtime GET-only probe with existing maintainer authentication. No production private signing keys, no mutation, no durable reservation. Not a live consequence acceptance.",
"independentAdoptionCredit": 0
}
2 changes: 1 addition & 1 deletion services/release-provider/src/policy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export function releaseSigner(env) {
}
async function anonymousGitHubJson(path) {
const response = await fetch("https://api.github.com/repos/AyobamiH/agentproof-release-canary" + path, {
method: "GET", redirect: "error", cache: "no-store",
method: "GET", redirect: "manual", cache: "no-store",
headers: { accept: "application/vnd.github+json", "user-agent": "agentproof-separate-release-signer/1.0" },
signal: AbortSignal.timeout(12_000),
});
Expand Down
28 changes: 27 additions & 1 deletion services/release-provider/test/provider.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { digest, stableJson } from "../../../dist/hash.js";
import { publicKeyFingerprint } from "../../../dist/signer.js";
import { verifyReleaseReceiptV2 } from "../../../dist/release-v1-receipt.js";
import { validateClaims, SUBJECT, CANARY_REPOSITORY, WORKFLOW } from "../src/identity.mjs";
import { publicReleaseReadback } from "../src/policy.mjs";
import { ReleaseFence, ReleaseReceiptLedger, handle } from "../src/worker.mjs";

const HEAD = "1".repeat(40);
Expand Down Expand Up @@ -76,7 +77,7 @@ function githubFixture(t, options={}) {
t.mock.method(globalThis,"fetch",async (input,init={})=>{
const url = new URL(String(input));
assert.equal(url.origin,"https://api.github.com");
assert.equal(init.redirect,"error");
assert.equal(init.redirect,"manual");
assert.match(init.headers["user-agent"], /^agentproof-/);
if (init.headers.authorization !== undefined)
assert.equal(init.headers.authorization,"Bearer test-ephemeral-gh-token");
Expand Down Expand Up @@ -306,3 +307,28 @@ test("recovery reservation cannot execute until a distinct signed committed-auth
assert.equal(api.mutationCount,1);

});


test("GitHub redirects cannot reserve a release or satisfy independent signer readback",async t=>{
let status=301,calls=[];
t.mock.method(globalThis,"fetch",async(input,init)=>{
assert.equal(new URL(String(input)).origin,"https://api.github.com");
assert.equal(init.method,"GET");
assert.equal(init.redirect,"manual");
calls.push({url:String(input),method:init.method});
return new Response("untrusted redirect body",{
status,headers:{location:"https://untrusted.invalid/steal","content-type":"text/plain"}
});
});
for(status of [301,302,303,307,308]){
const authority=env("approval");calls=[];
const rejected=await call("approval",authority,"/v1/prepare",{seed:seed()});
assert.equal(rejected.status,403);
assert.equal(rejected.json.error,"release_policy_rejected");
assert.equal(calls.length,1);
assert.equal(authority.ledger.size,0);
calls=[];
await assert.rejects(publicReleaseReadback(subject),/public_readback_unavailable/);
assert.equal(calls.length,1);
}
});
4 changes: 3 additions & 1 deletion src/release-v1-github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ export class GitHubReleaseV1Provider implements ReleaseV1Provider {
releaseAssert(typeof token === "string" && token.length >= 8 &&
token.length <= 4096 && /^[\x21-\x7e]+$/.test(token) && !controller.signal.aborted,
"github_token_unavailable");
// Workers reject redirect: error. Manual mode plus exact 200 validation
// refuses redirects without forwarding the short-lived token.
const response = await fetch(this.base + suffix, {
method, redirect: "error", cache: "no-store", signal: controller.signal,
method, redirect: "manual", cache: "no-store", signal: controller.signal,
headers: { "accept": "application/vnd.github+json", "content-type": "application/json",
"authorization": "Bearer " + token, "x-github-api-version": "2022-11-28",
"user-agent": "agentproof-release-provider/1.0" },
Expand Down
Loading