Dashboard › publish › Distillation
6d38f308-d452-4d9d-af41-262d7569f7d4["lore_tm_v1_FM0NR-31e0sJ2uIfUu63dWJWWhWkF0vmMsR7y7JjiKs","lore_tm_v1_5P5tYZ4-hbmWYZT0YBXv9uvnjGICsM6VycqjgL14f0s","lore_tm_v1_KiVSG8-g-LbJiLXjtFnmXqOnpcXRcbtxia5_o7aUVDs","lore_tm_v1_htDyzclO4cBYMxrbwRKm6in19lsiZ8kMJ5UjSZhKrIQ","lore_tm_v1_F3D-3hrajL3jnBrbwITCCuR3FNjQJUPxnYlX5IMmceE","lore_tm_v1_hIscDkXj_u5VyUdHVqxXyU49NN92RLnW1sfHL_ouuV4","lore_tm_v1_UP1YTUhcv-wFpjrr7tZxwIpdyE0e7h1e79s9POQPqKw"]
src/modules/approval-attestation.js defines requestDigest({ body, labels, title }) as a SHA-256 hex digest of JSON containing exact body, title, and dryRun, where dryRun is derived from whether labels contains { name: "dry-run" }; it throws "Invalid publish request" when body is not a string or labels is not an array.src/modules/approval-attestation.js binds approval, auto-approval, and CI-ready attestations to requestDigest(issue) and issue.title through createApprovalAttestation(), createAutoApprovalAttestation(), and createCiReadyAttestation(); CI-ready attestations additionally bind acceptedActor, stringified acceptedEventId, and ciReadyActor.src/modules/approval-attestation.js encodes attestations as base64url JSON inside HTML comments using prefixes <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready with suffix -->; corresponding parsers fail closed with null if required fields are missing or malformed.src/modules/approval-attestation.js selects the latest matching label event via decimal-string-safe compareEventIds(), avoiding numeric precision loss; invalid non-digit event IDs throw "Invalid issue event ID" and cause currentLabeledEvent() to return null. currentAcceptedEvent() targets accepted, while currentCiReadyEvent() targets ci-ready..github/workflows/publish.yml needs 4 event-digest checks rather than 3 because the post-authorization validation step is another live issue read and every live read must remain tied to the same triggering event snapshot.src/publish/__tests__/validate-approval-attestation.js coverage includes acceptance of the current trusted accepted event and rejection after title changes, body changes, mismatch with a poller snapshot, removal of accepted, issue closure, re-adding accepted under a later event ID, and substitution of a later attested approval for an earlier checked event.src/publish/validate-approval-attestation.js currently fetches the issue, all event pages, and all comment pages concurrently; pagination uses per_page=100, and authorization uses APPROVAL_TOKEN with GitHub API version 2026-03-10.validateApprovalAttestation() currently accepts a missing expectedRequestDigest through (!expectedRequestDigest || requestDigest(issue) === expectedRequestDigest) at line 76, while main() converts absent EXPECTED_REQUEST_DIGEST to undefined at line 129. Planned fix requires the digest at both the exported validateApprovalAttestation() boundary and executable main() environment boundary.validateApprovalAttestation() additionally requires the issue to be open, its title to equal issueTitle, the accepted label to be present, a current accepted event to exist, any supplied expectedAcceptedEvent to match actor and event ID, and a matching trusted approval attestation. With requireCiReadyAttestation = true, it also requires a current ci-ready event, the ci-ready label, and a matching CI-ready attestation.src/publish/record-ci-ready-attestation.js currently performs an optional digest comparison at line 51β(expectedRequestDigest && requestDigest(issue) !== expectedRequestDigest)βand main() passes process.env.EXPECTED_REQUEST_DIGEST || undefined at line 86; this is another live-only fallback targeted for mandatory fail-closed enforcement.recordCiReadyAttestation() concurrently retrieves the live issue, issue events, and authenticated GitHub login, then rejects with "The approval changed before CI could be marked ready" if the issue is not open, title differs, request digest differs when supplied, accepted is absent, no accepted event exists, or a supplied expectedAcceptedEvent differs. On success it returns createCiReadyAttestation({ acceptedEvent, ciReadyActor, issue }).src/publish/record-ci-ready-attestation.js executable currently requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, and APPROVAL_ISSUE_TITLE, but not EXPECTED_REQUEST_DIGEST; successful execution appends ci_ready_attestation=${attestation}\n to GITHUB_OUTPUT.