Skip to content

Comment Bar's diagnosis on the pull request from a write-scoped job - #64

Merged
gowtham0992 merged 1 commit into
mainfrom
bar-pr-comment
Aug 15, 2026
Merged

Comment Bar's diagnosis on the pull request from a write-scoped job#64
gowtham0992 merged 1 commit into
mainfrom
bar-pr-comment

Conversation

@gowtham0992

@gowtham0992 gowtham0992 commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Posts Bar's diagnosis back to the pull request, from a job that can write
comments and nothing else.

Trust boundary

permissions: {} at the workflow level, granted per job:

Job Permissions Holds
investigate actions: read, contents: read, pull-requests: read Bar credentials, evidence
comment contents: read, issues: write one encoded payload

The comment job receives no BAR_ACCESS_*, no evidence text, and no
Actions read, since GITHUB_TOKEN is scoped by the job's own
permissions. Both jobs check out github.workflow_sha with a SHA-pinned
actions/checkout and persist-credentials: false.

The payload crosses as a job output consumed through env:, never
interpolated into a run: line. It is base64url with padding stripped,
so its alphabet cannot express a newline or a workflow command, and the
8 KiB cap is enforced on the encoded length.

Destination authority

The comment target is the pull request the collector already validated
against GitHub: same repository, head SHA matching the run. Bar's
returned pull request number is cross-checked against that and rejected
on mismatch. It is never used to select where to comment, so a wrong
answer from Bar cannot redirect the comment to another issue.

Hostile model text

Diagnosis prose is NFKC-normalized first, so fullwidth forms unfold
before filtering. Line breaks become spaces; other control and format
characters are deleted, which keeps zero-width and bidi obfuscation from
surviving as separate words. URLs and bare domains are replaced, @,
<, >, & fold to lookalikes, and the result is Markdown-escaped.

Verified against 19 attack classes — mentions, HTML, Markdown links and
images, bare URLs and domains, javascript:, data:, fullwidth-encoded
URLs, bidi overrides, zero-width splits, newline and marker injection,
control characters, entities, tables, quotes, backticks. Zero escapes.
Worst-case rendering, four jobs with every field at maximum length and
entirely escapable, is 6,007 bytes against the 12 KiB cap.

Polling

GET only, so it cannot start, retry, or duplicate a Workflow or model
call. Bounded by a deadline, an 8 KiB response cap, and at most four
investigations. Summaries are checked field by field against the
collector's run, attempt, and pull request.

A total timeout produces a bounded "diagnosis unavailable" comment
instead of failing the job, because evidence ingestion succeeded and a
rerun updates the same comment in place. TLS certificate failures are
permanent rather than retried, so an intercepted connection is not
reported as an ordinary timeout.

Comment identity

One marker comment per pull request. A marker registers only when
github-actions[bot] authored it, so a user pasting the public marker
is ignored rather than wedging updates; two bot-authored markers still
fail closed. Ambiguous writes re-look-up and verify comment identity and
body before retrying, so a lost response cannot duplicate.

Release hygiene

Two narrow allowlist entries for the CI-only scripts that make outbound
calls. tests/test_bar_pr_comment.py drives fakes and needs no
exemption. Neither script ships: the wheel packages only link_mcp and
link_core.

Verification

Release hygiene passed, hygiene tests 11 passed, comment tests 24
passed, collector tests 37 passed, full suite 1071 passed, ruff clean,
actionlint clean, git diff --check clean.

Splits the workflow into a read-only investigation job and a comment job
that holds only contents:read and issues:write. The comment job receives
no Bar credentials, no evidence text, and no Actions-read token: the two
jobs communicate through one base64url job output whose alphabet cannot
express a newline or a workflow command, capped at 8 KiB after encoding.

The comment destination is the pull request the collector already
validated against GitHub. Bar's own pull request number is cross-checked
against it and never used to choose where to comment.

Model text is treated as hostile. Diagnosis prose is NFKC-normalized,
stripped of control and format characters, cleared of URLs and bare
domains, has mention and HTML characters folded to lookalikes, and is
Markdown-escaped, inside a comment bounded to 12 KiB.

Polling only ever issues GET, so it cannot start, retry, or duplicate a
Workflow or model call. A total polling timeout still produces a bounded
"diagnosis unavailable" comment rather than turning successful evidence
ingestion into a failed job, and a rerun updates that comment in place.
TLS certificate failures are permanent rather than retried.

Marker comments count only when github-actions[bot] wrote them, so a
user pasting the public marker cannot wedge Bar's updates; two
bot-authored markers still fail closed.

Allowlists the two new CI-only scripts in the release-hygiene network
check. The comment tests drive fakes and need no exemption.
@gowtham0992
gowtham0992 merged commit 8880eac into main Aug 15, 2026
10 checks passed
@gowtham0992
gowtham0992 deleted the bar-pr-comment branch August 15, 2026 21:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant