Add opaque LLM agent SHA attribution for issues, branches, PRs, and review handoffs #86

Closed
opened 2026-07-02 12:50:16 -05:00 by jcwalker3 · 2 comments
Owner

We need a safe way for each LLM/session/agent to identify its own work across issues, branches, PRs, and review handoffs without exposing an obvious human/model identity.

Current problem

The review/merge safety gate correctly uses the authenticated Gitea user/profile, not the LLM session identity. This must remain true. However, multiple LLM sessions may all authenticate through the same Gitea author account, usually jcwalker3, when creating implementation PRs. Later, another LLM session may be asked to review, but if its MCP server is still authenticated as jcwalker3 / gitea-default, it is blocked as the PR author. The LLM may also be confused because it did not personally write the code, even though Gitea sees it as the same authenticated author.

We need attribution that separates:

  • Gitea authenticated user/profile
  • opaque LLM agent/session identity
  • implementation author session
  • reviewer session
  • merge actor identity

Important safety rule

LLM agent identity must not replace the authenticated Gitea user/profile gates. Self-review/self-merge protections must still be enforced by Gitea authenticated user and MCP profile permissions. LLM agent identity is for attribution, routing, audit clarity, and operator workflow only.

Proposed identity format

Use an opaque SHA-like identifier instead of a friendly or obvious name.

Examples:

LLM-Agent-SHA: llm-8f3a9c2d6b41
LLM-Agent-SHA: llm-41d0e7aa9f2c
LLM-Agent-SHA: llm-b7c93d441a08

The value should:

  • be opaque
  • contain no model name
  • contain no human name
  • contain no email
  • contain no hostname
  • contain no token/secret
  • not be used as authentication
  • be stable for one session/workstream or one branch/PR
  • be safe to include in PR bodies, issue comments, and audit logs

Suggested generation

Generate a random or hash-derived short identifier such as:

llm-<12 hex chars>

Examples:

  • random 48-bit hex value
  • hash of non-secret session UUID
  • hash of local launcher session ID
  • operator-provided opaque ID

Do not derive it from:

  • Gitea token
  • email address
  • username
  • machine hostname
  • private path
  • model/provider name
  • conversation contents

Suggested PR body metadata block

LLM Handoff Metadata:
- LLM-Agent-SHA: llm-8f3a9c2d6b41
- LLM-Role: implementer
- Authenticated-Gitea-User: <whoami result>
- MCP-Profile: <profile name>
- Branch: <branch>
- Worktree: <worktree path>
- Self-review allowed: no

Suggested review metadata block

Review Metadata:
- LLM-Agent-SHA: llm-41d0e7aa9f2c
- LLM-Role: reviewer
- Authenticated-Gitea-User: <whoami result>
- MCP-Profile: <profile name>
- Eligibility: passed/failed

Acceptance criteria

  • Define the opaque LLM agent SHA convention.
  • Document how LLMs should generate or receive the SHA.
  • Document recommended lifetime:
    • per session,
    • per worktree,
    • or per PR/workstream.
  • Document where identity metadata should be recorded.
  • Ensure the SHA contains no human/model/provider-identifying information.
  • Ensure identity metadata contains no secrets, tokens, private paths beyond already-reported worktree paths, or credentials.
  • Ensure authenticated Gitea user/profile remains the only source of truth for review/merge eligibility.
  • Update PR handoff guidance to include LLM-Agent-SHA.
  • Update review prompts/guidance to distinguish:
    • "same LLM-Agent-SHA"
    • "same authenticated Gitea user"
    • "same MCP profile"
  • Add or update tests if MCP tool payloads or audit records are changed.
  • If MCP tooling is changed, include:
    • opaque agent SHA in safe audit events
    • no behavior change to merge/review gates
    • no bypass of allowed_operations
    • no bypass of self-review/self-merge protection

Non-goals

  • Do not allow LLM-Agent-SHA to override Gitea identity.
  • Do not allow an author-authenticated session to review or merge because it has a different LLM-Agent-SHA.
  • Do not encode model/provider/human identity in the SHA.
  • Do not store secrets in identity metadata.
  • Do not create an "everything is allowed" reviewer identity.
  • Do not weaken prgs-reviewer / gitea-default profile separation.

Open questions

  • Should the opaque SHA be generated by the MCP launcher or chosen by the LLM at session start?
  • Should it live in environment variables, for example LLM_AGENT_SHA and LLM_AGENT_ROLE?
  • Should gitea_whoami include both Gitea identity and LLM agent SHA?
  • Should PR creation tools automatically add the metadata block to PR bodies?
  • Should audit logs require LLM-Agent-SHA on all mutating actions?
  • Should branch/worktree naming include the SHA, or should it stay only in metadata?
We need a safe way for each LLM/session/agent to identify its own work across issues, branches, PRs, and review handoffs without exposing an obvious human/model identity. ## Current problem The review/merge safety gate correctly uses the authenticated Gitea user/profile, not the LLM session identity. This must remain true. However, multiple LLM sessions may all authenticate through the same Gitea author account, usually `jcwalker3`, when creating implementation PRs. Later, another LLM session may be asked to review, but if its MCP server is still authenticated as `jcwalker3 / gitea-default`, it is blocked as the PR author. The LLM may also be confused because it did not personally write the code, even though Gitea sees it as the same authenticated author. We need attribution that separates: * Gitea authenticated user/profile * opaque LLM agent/session identity * implementation author session * reviewer session * merge actor identity ## Important safety rule LLM agent identity must **not** replace the authenticated Gitea user/profile gates. Self-review/self-merge protections must still be enforced by Gitea authenticated user and MCP profile permissions. LLM agent identity is for attribution, routing, audit clarity, and operator workflow only. ## Proposed identity format Use an opaque SHA-like identifier instead of a friendly or obvious name. Examples: ```text LLM-Agent-SHA: llm-8f3a9c2d6b41 LLM-Agent-SHA: llm-41d0e7aa9f2c LLM-Agent-SHA: llm-b7c93d441a08 ``` The value should: * be opaque * contain no model name * contain no human name * contain no email * contain no hostname * contain no token/secret * not be used as authentication * be stable for one session/workstream or one branch/PR * be safe to include in PR bodies, issue comments, and audit logs ## Suggested generation Generate a random or hash-derived short identifier such as: ```text llm-<12 hex chars> ``` Examples: * random 48-bit hex value * hash of non-secret session UUID * hash of local launcher session ID * operator-provided opaque ID Do **not** derive it from: * Gitea token * email address * username * machine hostname * private path * model/provider name * conversation contents ## Suggested PR body metadata block ```text LLM Handoff Metadata: - LLM-Agent-SHA: llm-8f3a9c2d6b41 - LLM-Role: implementer - Authenticated-Gitea-User: <whoami result> - MCP-Profile: <profile name> - Branch: <branch> - Worktree: <worktree path> - Self-review allowed: no ``` ## Suggested review metadata block ```text Review Metadata: - LLM-Agent-SHA: llm-41d0e7aa9f2c - LLM-Role: reviewer - Authenticated-Gitea-User: <whoami result> - MCP-Profile: <profile name> - Eligibility: passed/failed ``` ## Acceptance criteria * Define the opaque LLM agent SHA convention. * Document how LLMs should generate or receive the SHA. * Document recommended lifetime: * per session, * per worktree, * or per PR/workstream. * Document where identity metadata should be recorded. * Ensure the SHA contains no human/model/provider-identifying information. * Ensure identity metadata contains no secrets, tokens, private paths beyond already-reported worktree paths, or credentials. * Ensure authenticated Gitea user/profile remains the only source of truth for review/merge eligibility. * Update PR handoff guidance to include `LLM-Agent-SHA`. * Update review prompts/guidance to distinguish: * "same LLM-Agent-SHA" * "same authenticated Gitea user" * "same MCP profile" * Add or update tests if MCP tool payloads or audit records are changed. * If MCP tooling is changed, include: * opaque agent SHA in safe audit events * no behavior change to merge/review gates * no bypass of `allowed_operations` * no bypass of self-review/self-merge protection ## Non-goals * Do not allow LLM-Agent-SHA to override Gitea identity. * Do not allow an author-authenticated session to review or merge because it has a different LLM-Agent-SHA. * Do not encode model/provider/human identity in the SHA. * Do not store secrets in identity metadata. * Do not create an "everything is allowed" reviewer identity. * Do not weaken `prgs-reviewer` / `gitea-default` profile separation. ## Open questions * Should the opaque SHA be generated by the MCP launcher or chosen by the LLM at session start? * Should it live in environment variables, for example `LLM_AGENT_SHA` and `LLM_AGENT_ROLE`? * Should `gitea_whoami` include both Gitea identity and LLM agent SHA? * Should PR creation tools automatically add the metadata block to PR bodies? * Should audit logs require `LLM-Agent-SHA` on all mutating actions? * Should branch/worktree naming include the SHA, or should it stay only in metadata?
jcwalker3 added the mcpsecurityworkflowenhancement labels 2026-07-02 12:50:25 -05:00
Owner

Discussion: Proposed LLM-Agent-SHA Decision and Implementation Shape

This is LLM feedback for discussion only. It is not yet the final owner decision.

1. Recommended Direction

Adopt LLM-Agent-SHA as informational/audit metadata only.

It is useful for tracing multi-agent work, debugging handoffs, and understanding which LLM session produced or reviewed a given artifact. However, it must never be used for authorization, review eligibility, merge eligibility, or profile permissions.

The security boundary remains:

  • authenticated Gitea user
  • active MCP profile
  • allowed_operations
  • self-review/self-merge checks

If two different LLM sessions have different LLM-Agent-SHA values but authenticate as the same Gitea user, the safety gates must treat them as the same actor.

2. Proposed Near-Term Implementation

Possible implementation shape:

  • Support an optional LLM-Agent-SHA metadata value.
  • Allow interim self-generated values such as:
llm-<12 hex chars>
  • Prefer future launcher/environment injection, for example:
LLM_AGENT_SHA=llm-8f3a9c2d6b41
LLM_AGENT_ROLE=implementer
  • Include the SHA in audit records when audit logging is enabled.
  • Include the SHA in PR/issue/review handoff metadata when provided.

Possible visibility options:

LLM Handoff Metadata:
- LLM-Agent-SHA: llm-8f3a9c2d6b41
- LLM-Role: implementer
- Authenticated-Gitea-User: jcwalker3
- MCP-Profile: gitea-default

or a less visible HTML comment:

<!-- llm-agent-sha: llm-8f3a9c2d6b41 -->

3. Security Requirement

Add an explicit negative test proving that LLM-Agent-SHA does not affect authorization.

Required test scenario:

User A + SHA 1 creates a PR.
User A + SHA 2 attempts to review, approve, or merge that PR.
Expected result: rejected as self-review/self-merge.

This test must prove that a different SHA does not bypass the Gitea authenticated-user safety gate.

4. Deferred Items

Defer:

  • strict launcher enforcement
  • centralized cross-agent lineage tracking
  • release/orchestrator tracking
  • any use of SHA as a security decision input

These can wait until the broader MCP Control Plane architecture is clearer.

5. Risks

False sense of security

Operators or LLMs may mistakenly think different SHAs mean separate review identities.

Mitigation:
Documentation and tests must state clearly that only Gitea user/profile controls eligibility.

UI clutter

Adding SHA metadata to every issue/comment/PR may clutter Gitea.

Mitigation:
Use a small handoff block only where useful, or HTML comments for low-visibility attribution.

Spoofing

If an LLM self-generates the SHA, it can be changed or spoofed.

Mitigation:
Accept this for phase 0 because SHA is informational only. Longer term, prefer launcher-injected SHA.

6. Questions for Owner Decision

Before implementation, decide:

  1. Should phase 0 be documentation-only self-generated SHA?
  2. Should phase 1 use launcher/env injection?
  3. Should gitea_whoami return LLM-Agent-SHA and LLM-Agent-Role?
  4. Should PR creation tools automatically append metadata?
  5. Should audit logs require SHA on all mutating actions?
  6. Should SHA be visible in markdown, hidden in HTML comments, or both?
  7. Should branch names stay human-readable and avoid SHA? Recommended: yes.

7. Current Recommendation

Recommended phased approach:

  1. Phase 0: Document convention. LLM self-generates llm-<12 hex> in handoff metadata.
  2. Phase 1: MCP launcher injects LLM_AGENT_SHA and LLM_AGENT_ROLE.
  3. Phase 2: gitea_whoami, audit logs, and PR creation include the metadata automatically.
  4. Never: use LLM-Agent-SHA for review/merge eligibility.
## Discussion: Proposed `LLM-Agent-SHA` Decision and Implementation Shape This is LLM feedback for discussion only. It is **not yet the final owner decision**. ### 1. Recommended Direction Adopt `LLM-Agent-SHA` as **informational/audit metadata only**. It is useful for tracing multi-agent work, debugging handoffs, and understanding which LLM session produced or reviewed a given artifact. However, it must never be used for authorization, review eligibility, merge eligibility, or profile permissions. The security boundary remains: - authenticated Gitea user - active MCP profile - `allowed_operations` - self-review/self-merge checks If two different LLM sessions have different `LLM-Agent-SHA` values but authenticate as the same Gitea user, the safety gates must treat them as the same actor. ### 2. Proposed Near-Term Implementation Possible implementation shape: - Support an optional `LLM-Agent-SHA` metadata value. - Allow interim self-generated values such as: ```text llm-<12 hex chars> ``` * Prefer future launcher/environment injection, for example: ```text LLM_AGENT_SHA=llm-8f3a9c2d6b41 LLM_AGENT_ROLE=implementer ``` * Include the SHA in audit records when audit logging is enabled. * Include the SHA in PR/issue/review handoff metadata when provided. Possible visibility options: ```markdown LLM Handoff Metadata: - LLM-Agent-SHA: llm-8f3a9c2d6b41 - LLM-Role: implementer - Authenticated-Gitea-User: jcwalker3 - MCP-Profile: gitea-default ``` or a less visible HTML comment: ```html <!-- llm-agent-sha: llm-8f3a9c2d6b41 --> ``` ### 3. Security Requirement Add an explicit negative test proving that `LLM-Agent-SHA` does not affect authorization. Required test scenario: ```text User A + SHA 1 creates a PR. User A + SHA 2 attempts to review, approve, or merge that PR. Expected result: rejected as self-review/self-merge. ``` This test must prove that a different SHA does not bypass the Gitea authenticated-user safety gate. ### 4. Deferred Items Defer: * strict launcher enforcement * centralized cross-agent lineage tracking * release/orchestrator tracking * any use of SHA as a security decision input These can wait until the broader MCP Control Plane architecture is clearer. ### 5. Risks #### False sense of security Operators or LLMs may mistakenly think different SHAs mean separate review identities. Mitigation: Documentation and tests must state clearly that only Gitea user/profile controls eligibility. #### UI clutter Adding SHA metadata to every issue/comment/PR may clutter Gitea. Mitigation: Use a small handoff block only where useful, or HTML comments for low-visibility attribution. #### Spoofing If an LLM self-generates the SHA, it can be changed or spoofed. Mitigation: Accept this for phase 0 because SHA is informational only. Longer term, prefer launcher-injected SHA. ### 6. Questions for Owner Decision Before implementation, decide: 1. Should phase 0 be documentation-only self-generated SHA? 2. Should phase 1 use launcher/env injection? 3. Should `gitea_whoami` return `LLM-Agent-SHA` and `LLM-Agent-Role`? 4. Should PR creation tools automatically append metadata? 5. Should audit logs require SHA on all mutating actions? 6. Should SHA be visible in markdown, hidden in HTML comments, or both? 7. Should branch names stay human-readable and avoid SHA? Recommended: yes. ### 7. Current Recommendation Recommended phased approach: 1. **Phase 0:** Document convention. LLM self-generates `llm-<12 hex>` in handoff metadata. 2. **Phase 1:** MCP launcher injects `LLM_AGENT_SHA` and `LLM_AGENT_ROLE`. 3. **Phase 2:** `gitea_whoami`, audit logs, and PR creation include the metadata automatically. 4. **Never:** use `LLM-Agent-SHA` for review/merge eligibility.
Author
Owner

Owner Decision: Phase 0 LLM-Agent-SHA Attribution

Approved direction:

LLM-Agent-SHA is informational attribution metadata only.

It must never be used for authentication, authorization, review eligibility, merge eligibility, profile permissions, or any other security decision.

The security gates remain:

  • authenticated Gitea user
  • active MCP profile
  • allowed_operations
  • self-review/self-merge checks

Different LLM-Agent-SHA values under the same authenticated Gitea user are still the same actor for review/merge safety.

Phase 0 — Approved Now

Implement Phase 0 only:

  1. Document the LLM-Agent-SHA convention.

  2. Use format:

    llm-<12 lowercase hex chars>
    

    Recommended validation:

    ^llm-[0-9a-f]{12}$
    
  3. SHA lifetime:

    per PR/workstream
    

    A per-session SHA is acceptable if it maps cleanly to one workstream.

  4. The SHA should be included in handoff metadata blocks, for example:

    LLM Handoff Metadata:
    - LLM-Agent-SHA: llm-8f3a9c2d6b41
    - LLM-Role: implementer
    - Authenticated-Gitea-User: jcwalker3
    - MCP-Profile: gitea-default
    - Branch: docs/example-branch
    - Worktree: branches/docs-example-branch
    - Self-review allowed: no
    
  5. Review handoffs should include:

    Review Metadata:
    - LLM-Agent-SHA: llm-41d0e7aa9f2c
    - LLM-Role: reviewer
    - Authenticated-Gitea-User: sysadmin
    - MCP-Profile: prgs-reviewer
    - Eligibility: passed
    
  6. Add or update documentation so LLMs and operators clearly distinguish:

    • same LLM-Agent-SHA
    • same authenticated Gitea user
    • same MCP profile
  7. Add explicit negative tests proving:

    User A + SHA 1 creates a PR.
    User A + SHA 2 attempts review/approve/merge.
    Expected result: rejected as self-review/self-merge.
    
  8. The tests must prove that LLM-Agent-SHA is never consulted by the eligibility logic.

Visibility Decision

Use visible markdown metadata blocks for Phase 0.

Do not use hidden HTML comments yet. Hidden comments may be reconsidered later if UI clutter becomes a problem.

Branch/Worktree Decision

Do not put LLM-Agent-SHA in branch names or worktree names.

Branches and worktrees should remain human-readable and issue-based.

Deferred

Do not implement these in Phase 0:

  • launcher-enforced SHA generation
  • LLM_AGENT_SHA / LLM_AGENT_ROLE environment injection
  • gitea_whoami returning SHA/role
  • automatic PR body injection by MCP tools
  • audit schema changes requiring SHA
  • release/orchestrator lineage tracking

These may become follow-up phases after Phase 0 lands.

Never Allowed

The SHA must never:

  • override Gitea authenticated user checks
  • override MCP profile checks
  • bypass allowed_operations
  • bypass self-review/self-merge protection
  • encode model name, provider name, human name, email, hostname, token, private path, or conversation contents
  • be treated as proof of identity

Implementation Scope for #86

For this issue, implement Phase 0 only unless a follow-up owner decision expands scope.

Expected scope:

  • documentation updates
  • handoff/review template updates
  • negative tests proving SHA cannot bypass self-review/self-merge

No launcher work, no audit schema changes, and no automatic PR injection in this phase.

## Owner Decision: Phase 0 `LLM-Agent-SHA` Attribution Approved direction: `LLM-Agent-SHA` is **informational attribution metadata only**. It must never be used for authentication, authorization, review eligibility, merge eligibility, profile permissions, or any other security decision. The security gates remain: - authenticated Gitea user - active MCP profile - `allowed_operations` - self-review/self-merge checks Different `LLM-Agent-SHA` values under the same authenticated Gitea user are still the same actor for review/merge safety. ### Phase 0 — Approved Now Implement Phase 0 only: 1. Document the `LLM-Agent-SHA` convention. 2. Use format: ```text llm-<12 lowercase hex chars> ``` Recommended validation: ```text ^llm-[0-9a-f]{12}$ ``` 3. SHA lifetime: ```text per PR/workstream ``` A per-session SHA is acceptable if it maps cleanly to one workstream. 4. The SHA should be included in handoff metadata blocks, for example: ```markdown LLM Handoff Metadata: - LLM-Agent-SHA: llm-8f3a9c2d6b41 - LLM-Role: implementer - Authenticated-Gitea-User: jcwalker3 - MCP-Profile: gitea-default - Branch: docs/example-branch - Worktree: branches/docs-example-branch - Self-review allowed: no ``` 5. Review handoffs should include: ```markdown Review Metadata: - LLM-Agent-SHA: llm-41d0e7aa9f2c - LLM-Role: reviewer - Authenticated-Gitea-User: sysadmin - MCP-Profile: prgs-reviewer - Eligibility: passed ``` 6. Add or update documentation so LLMs and operators clearly distinguish: * same `LLM-Agent-SHA` * same authenticated Gitea user * same MCP profile 7. Add explicit negative tests proving: ```text User A + SHA 1 creates a PR. User A + SHA 2 attempts review/approve/merge. Expected result: rejected as self-review/self-merge. ``` 8. The tests must prove that `LLM-Agent-SHA` is never consulted by the eligibility logic. ### Visibility Decision Use visible markdown metadata blocks for Phase 0. Do **not** use hidden HTML comments yet. Hidden comments may be reconsidered later if UI clutter becomes a problem. ### Branch/Worktree Decision Do **not** put `LLM-Agent-SHA` in branch names or worktree names. Branches and worktrees should remain human-readable and issue-based. ### Deferred Do not implement these in Phase 0: * launcher-enforced SHA generation * `LLM_AGENT_SHA` / `LLM_AGENT_ROLE` environment injection * `gitea_whoami` returning SHA/role * automatic PR body injection by MCP tools * audit schema changes requiring SHA * release/orchestrator lineage tracking These may become follow-up phases after Phase 0 lands. ### Never Allowed The SHA must never: * override Gitea authenticated user checks * override MCP profile checks * bypass `allowed_operations` * bypass self-review/self-merge protection * encode model name, provider name, human name, email, hostname, token, private path, or conversation contents * be treated as proof of identity ### Implementation Scope for #86 For this issue, implement Phase 0 only unless a follow-up owner decision expands scope. Expected scope: * documentation updates * handoff/review template updates * negative tests proving SHA cannot bypass self-review/self-merge No launcher work, no audit schema changes, and no automatic PR injection in this phase.
sysadmin added the status:in-progress label 2026-07-02 13:25:14 -05:00
sysadmin removed the status:in-progress label 2026-07-02 14:01:07 -05:00
Sign in to join this conversation.