Migrates go.mod + the single Go import + a stale go.mod replace-comment + README require example off the dead github.com/Molecule-AI/ identity and onto the vanity host go.moleculesai.app, owned by us. Adds a structural lint test that walks every *.go / *.mod / Dockerfile / *.md and rejects future re-introduction of either the literal github.com/Molecule-AI/ string or the historical Molecule-AI/molecule-monorepo path. Why a vanity host and not git.moleculesai.app/molecule-ai/...: the latter just relocates the lock-in. 2026-05-06 didn't teach us 'Gitea > GitHub'; it taught us 'vendor URLs in source code are a future incident'. With go.moleculesai.app, the next SCM migration edits one config (the responder) instead of every import statement. See internal#71 for the full rationale + the alternatives rejected. Smoke-validation for this migration sweep — chosen as the first PR because it has the smallest blast radius (1 import line). Following PRs: molecule-cli, molecule-controlplane, molecule-core (parallel after this lands). Test plan: - go build ./... — clean - go test ./... — internal/ghidentity green - TestNoLegacyGitHubImportPaths — passes on clean tree, FAILS on injected canary string (mutation-tested before commit) Open dependency: go.moleculesai.app responder must be deployed before external 'go install go.moleculesai.app/plugin/gh-identity@latest' works. Internal builds are unaffected (self-referential module path, no external fetch needed). Responder code prepared in worker.js; deploy tracked separately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
4.4 KiB
Markdown
120 lines
4.4 KiB
Markdown
# molecule-ai-plugin-gh-identity
|
|
|
|
Injects per-agent identity into workspace env so every `gh` CLI call
|
|
carries agent attribution — without needing a distinct GitHub account per
|
|
agent.
|
|
|
|
## Problem
|
|
|
|
All agents in a Molecule fleet share one GitHub PAT. When an agent runs:
|
|
|
|
```
|
|
gh issue create --assignee @me ...
|
|
gh pr comment ...
|
|
```
|
|
|
|
`@me` resolves to the PAT owner (the CEO). Every issue, PR, and comment
|
|
gets attributed to one person, making audit impossible and flooding that
|
|
person's notifications. See [molecule-core#1957].
|
|
|
|
GitHub's identity model doesn't scale the way agent fleets do: creating N
|
|
machine users requires N emails + seats; creating N GitHub Apps requires
|
|
N manual UI round-trips. Neither is batch-generatable.
|
|
|
|
## Approach
|
|
|
|
Work around the identity model with a convention, enforced by a tiny
|
|
shell wrapper and this plugin's env injection.
|
|
|
|
1. Plugin injects per-workspace env: `MOLECULE_AGENT_ROLE`,
|
|
`MOLECULE_OWNER`, `MOLECULE_ATTRIBUTION_BADGE`.
|
|
2. The workspace base image ships a `gh` wrapper (`/usr/local/bin/gh`)
|
|
that reads `$MOLECULE_AGENT_ROLE` and:
|
|
- prepends an attribution block to every `issue comment` / `pr
|
|
comment` / `issue create --body` / `pr create --body`
|
|
- rewrites `--assignee @me` to `--assignee $MOLECULE_OWNER` (or
|
|
strips it entirely)
|
|
- emits an audit line to `/var/log/molecule-gh.ndjson`
|
|
3. A `git` wrapper does the same for `Co-authored-by:` on commits.
|
|
|
|
The wrapper script is shipped embedded in the plugin (`wrapper.sh`) and
|
|
installed by each workspace-template's `install.sh` when the plugin is
|
|
active. Plugin → env injection; template → file write.
|
|
|
|
## What this plugin is NOT
|
|
|
|
- NOT a GitHub App installer. Existing `molecule-ai-plugin-github-app-auth`
|
|
handles App-based auth; this plugin is additive and does not conflict.
|
|
- NOT a machine-user provisioning tool. There are no distinct GitHub
|
|
identities; attribution is text-based.
|
|
- NOT a per-agent rate limiter or cost accounter (future work; see #1957
|
|
follow-ups).
|
|
|
|
## Env vars injected
|
|
|
|
| Name | Source | Example |
|
|
|---|---|---|
|
|
| `MOLECULE_AGENT_ROLE` | workspace metadata (`role` field) | `PMM-Lead` |
|
|
| `MOLECULE_OWNER` | plugin config (role → owner map) | `HongmingWang-Rabbit` |
|
|
| `MOLECULE_ATTRIBUTION_BADGE` | computed | `🤖 [Agent: PMM-Lead · ws-a0689c35]` |
|
|
| `MOLECULE_GH_WRAPPER_SHA` | computed | hash of wrapper.sh for version pinning |
|
|
|
|
## Plugin manifest (v1)
|
|
|
|
This plugin ships as a v1 plugin (matching `molecule-ai-plugin-github-app-auth`).
|
|
Migration to [plugin-architecture-v2] happens in phase 6 of that plan.
|
|
The v1 shape here is intentionally structured so v2 migration is mostly a
|
|
manifest rename:
|
|
|
|
- `EnvMutator.MutateEnv` → v2's `contributions.env` + `hooks.env_refresh`
|
|
- Role→owner map in `config.yaml` → v2's `spec.config`
|
|
- Wrapper script shipping → v2's `contributions.files` (new axis)
|
|
|
|
## Install (v1)
|
|
|
|
Monorepo side:
|
|
```
|
|
manifest.json:plugins += {name: "gh-identity", repo: "Molecule-AI/molecule-ai-plugin-gh-identity", ref: "main"}
|
|
workspace-server/go.mod: require go.moleculesai.app/plugin/gh-identity
|
|
workspace-server/cmd/server/main.go: pluginloader.BuildRegistry()
|
|
```
|
|
|
|
Env (operator):
|
|
```
|
|
MOLECULE_GH_IDENTITY_CONFIG_FILE=/path/to/config.yaml
|
|
```
|
|
|
|
## Config
|
|
|
|
```yaml
|
|
# config.yaml — role → owner map (used for `@me` rewrite)
|
|
roles:
|
|
PMM-Lead: { owner: HongmingWang-Rabbit }
|
|
Dev-Lead: { owner: HongmingWang-Rabbit }
|
|
Research-Lead:{ owner: HongmingWang-Rabbit }
|
|
default: { owner: HongmingWang-Rabbit }
|
|
```
|
|
|
|
## Capabilities requested (v2 forward-compat)
|
|
|
|
When v2 enforcement lands, this plugin will declare:
|
|
|
|
- `workspace:env_inject` — required
|
|
- `workspace:file_write:/usr/local/bin/gh` — required (via template install.sh)
|
|
- `audit:emit` — required
|
|
- `network_egress:api.github.com` — required (wrapper makes API calls via real gh)
|
|
|
|
No broader capabilities. In particular: **no secret access** (PAT is
|
|
shared and platform-managed, not in plugin scope).
|
|
|
|
## Related
|
|
|
|
- molecule-core#1957 — agent identity collapse (this plugin's driver)
|
|
- molecule-core#1933 — GH_TOKEN refresh (separate concern; handled by
|
|
github-app-auth plugin)
|
|
- internal `product/plugin-architecture-v2.md` — target arch for v2
|
|
migration
|
|
|
|
[molecule-core#1957]: https://git.moleculesai.app/molecule-ai/molecule-core/issues/1957
|
|
[plugin-architecture-v2]: https://git.moleculesai.app/molecule-ai/internal/src/branch/main/product/plugin-architecture-v2.md
|