ward git ... should come with pre-configured forgejo auth #507

Closed
opened 2026-07-02 04:13:09 +00:00 by coilysiren · 6 comments
Owner

The problem

I ran ward git push and it prompted me for my username and password unexpectedly

Proposed change

ward git push figures out auth on its own

Alternatives considered

No response

Before filing

  • I searched existing issues and this is not a duplicate.
  • This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
### The problem I ran `ward git push` and it prompted me for my username and password unexpectedly ### Proposed change `ward git push` figures out auth on its own ### Alternatives considered _No response_ ### Before filing - [x] I searched existing issues and this is not a duplicate. - [x] This stays within ward's scope (the dev-verb gate / agent driver), not a personal-infra or downstream-repo verb.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-507 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T17:36:03Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-507` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T17:36:03Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - ward git fetch/pull/push/clone now inject URL-scoped Forgejo Basic-auth so they never hit the username/password prompt

Retrospective: this one was clean to reason about once I traced how the container already solves the same problem. The container writes a store credential helper from FORGEJO_TOKEN; the host ward git path had no equivalent, so it fell through to git's interactive prompt. The satisfying part was that ward already had every piece I needed - forgejoTokenResolver for the token, cli-guard's passthrough.WithEnvFunc hook for env injection - so the change is mostly wiring, not new machinery.

The one real design call was keeping the token out of the audit row. Injecting it as git -c http.<url>.extraheader=... would have leaked it into argv, so I went with GIT_CONFIG_* env instead. That also gives free URL-scoping: the header only rides requests to canonical Forgejo, never a github or third-party remote sharing the command - verified in real git with --get-urlmatch, and end-to-end with GIT_TRACE_CURL showing the Authorization: Basic header going out with no prompt.

Confidence is high. Best-effort resolution means a token-less host just degrades to today's behavior. Two honest rough edges: (1) the token now resolves on every push where $FORGEJO_TOKEN is unset, which can add an SSM round-trip - acceptable, since that's the only case that needs it; (2) a caller who pre-exports GIT_CONFIG_COUNT in their shell could shadow the injection due to first-wins duplicate-env semantics on Linux - I offset the index to never clobber their config, but the pathological case degrades to a prompt rather than misbehaving. Neither seems worth a follow-up issue yet.

WARD-OUTCOME: done - ward git fetch/pull/push/clone now inject URL-scoped Forgejo Basic-auth so they never hit the username/password prompt Retrospective: this one was clean to reason about once I traced how the container already solves the same problem. The container writes a `store` credential helper from `FORGEJO_TOKEN`; the host `ward git` path had no equivalent, so it fell through to git's interactive prompt. The satisfying part was that ward already had every piece I needed - `forgejoTokenResolver` for the token, cli-guard's `passthrough.WithEnvFunc` hook for env injection - so the change is mostly wiring, not new machinery. The one real design call was keeping the token out of the audit row. Injecting it as `git -c http.<url>.extraheader=...` would have leaked it into argv, so I went with `GIT_CONFIG_*` env instead. That also gives free URL-scoping: the header only rides requests to canonical Forgejo, never a github or third-party remote sharing the command - verified in real git with `--get-urlmatch`, and end-to-end with `GIT_TRACE_CURL` showing the `Authorization: Basic` header going out with no prompt. Confidence is high. Best-effort resolution means a token-less host just degrades to today's behavior. Two honest rough edges: (1) the token now resolves on every push where `$FORGEJO_TOKEN` is unset, which can add an SSM round-trip - acceptable, since that's the only case that needs it; (2) a caller who pre-exports `GIT_CONFIG_COUNT` in their shell could shadow the injection due to first-wins duplicate-env semantics on Linux - I offset the index to never clobber their config, but the pathological case degrades to a prompt rather than misbehaving. Neither seems worth a follow-up issue yet.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-507 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-507` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-507 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-507` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-507 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-507` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-04T08:28:20Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - already landed in 13678d1 (ancestor of main, closes #507); verified merged state builds and passes git/auth tests, no new work needed

I picked this up expecting to implement it and instead found it already done. Commit 13678d1 ("feat(git): pre-configure Forgejo auth for ward git network verbs") is already an ancestor of main, my branch issue-507 sits exactly on main, and this issue is already closed. So this was a re-dispatch of work a prior run finished on 2026-07-03.

Rather than fabricate a redundant change, I verified the landed state instead: the auth wiring is coherent across git.go (net verbs get passthrough.WithEnvFunc), git_auth.go (Forgejo token resolved as ward ops forgejo does, injected as a URL-scoped GIT_CONFIG_* extraheader so it stays off argv/the audit row), and git_clone.go (same env on the clone path). go build ./... is green and the git/auth tests pass.

Confidence is high that #507 is genuinely resolved. The only surprise was the dispatch itself — three back-to-back reservation comments today suggest the container restarted a few times against an issue that was already closed. Nothing to file as a follow-up on the feature; if anything, the meta-observation is that a re-dispatch guard against an already-closed/already-landed issue could save a container spin, but that's an agent-driver concern, not this issue's.

WARD-OUTCOME: done - already landed in 13678d1 (ancestor of main, closes #507); verified merged state builds and passes git/auth tests, no new work needed I picked this up expecting to implement it and instead found it already done. Commit `13678d1` ("feat(git): pre-configure Forgejo auth for ward git network verbs") is already an ancestor of `main`, my branch `issue-507` sits exactly on `main`, and this issue is already closed. So this was a re-dispatch of work a prior run finished on 2026-07-03. Rather than fabricate a redundant change, I verified the landed state instead: the auth wiring is coherent across `git.go` (net verbs get `passthrough.WithEnvFunc`), `git_auth.go` (Forgejo token resolved as `ward ops forgejo` does, injected as a URL-scoped `GIT_CONFIG_*` extraheader so it stays off argv/the audit row), and `git_clone.go` (same env on the clone path). `go build ./...` is green and the git/auth tests pass. Confidence is high that #507 is genuinely resolved. The only surprise was the dispatch itself — three back-to-back reservation comments today suggest the container restarted a few times against an issue that was already closed. Nothing to file as a follow-up on the feature; if anything, the meta-observation is that a re-dispatch guard against an already-closed/already-landed issue could save a container spin, but that's an agent-driver concern, not this issue's.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#507
No description provided.