Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ e2e-test: e2e-playwright
$(MAKE) e2e-export-session; \
export E2E_GITHUB_SESSION_FILE="$(E2E_SESSION_FILE)"; \
fi; \
go test -tags e2e -v -count=1 -timeout 4m ./e2e/admin/
go test -tags e2e -v -count=1 -timeout 10m ./e2e/admin/

e2e-export-session: e2e-playwright
@if [ -n "$$E2E_GITHUB_PASSWORD_FILE" ] && [ -z "$$E2E_GITHUB_PASSWORD" ]; then \
Expand Down
61 changes: 0 additions & 61 deletions dispatch/github/workflows/code.yml

This file was deleted.

67 changes: 0 additions & 67 deletions dispatch/github/workflows/review.yml

This file was deleted.

60 changes: 0 additions & 60 deletions dispatch/github/workflows/triage.yml

This file was deleted.

1 change: 1 addition & 0 deletions docs/ADRs/0007-per-role-github-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ The installer checks for existing app installations before creating new ones. If
- PEMs are write-once secrets: lost keys require app deletion and recreation.
- The per-app model scales linearly with roles. Adding a new role means creating a new app — no shared credential rotation needed.
- GitLab and Forgejo will need equivalent per-role identity mechanisms when their forge implementations are built.
- **Permission escalation note:** The `fullsend` orchestrator app requires `workflows: write` (combined with `contents: write`) to create and update shim workflow files in enrolled repos during enrollment reconciliation. A compromise of this app's private key would allow an attacker to deploy arbitrary workflow files to all installed repos. Mitigations: (1) the app should be installed on specific repos, not org-wide; (2) the PEM is stored as a repo-level secret on `.fullsend`, limiting access to that repo's workflows; (3) per-role workflows validate `source_repo` against the config allowlist before generating tokens.
4 changes: 3 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ Infrastructure platform choice and configuration are specified in the adopting o

- Forge abstraction: all forge operations go through the `forge.Client` interface, keeping the rest of the codebase forge-agnostic ([ADR 0005](ADRs/0005-forge-abstraction-layer.md)).
- Installation model: ordered layer stack (install forward, uninstall reverse, analyze for status reporting) with idempotent operations. Current stack: config-repo → workflows → secrets → inference → dispatch-token → enrollment ([ADR 0006](ADRs/0006-ordered-layer-model.md)).
- Cross-repo dispatch: `workflow_dispatch` with an org-level dispatch token replaces `workflow_call`, keeping App PEM secrets in the config repo ([ADR 0008](ADRs/0008-workflow-dispatch-for-cross-repo-dispatch.md)).
- Cross-repo dispatch: per-role `workflow_dispatch` workflows (`triage.yml`, `code.yml`, `review.yml`) with an org-level dispatch token, keeping App PEM secrets in the config repo ([ADR 0008](ADRs/0008-workflow-dispatch-for-cross-repo-dispatch.md)).
- Shim workflow security: `pull_request_target` prevents PR authors from modifying the shim to exfiltrate the dispatch token ([ADR 0009](ADRs/0009-pull-request-target-in-shim-workflows.md)).
- Repo maintenance: a workflow in `.fullsend` (`.github/workflows/repo-maintenance.yml`) reconciles enrollment shims in target repos when `config.yaml` changes or on manual dispatch. The CLI's `EnrollmentLayer.Install()` dispatches this workflow via `workflow_dispatch` and monitors it for completion, then reports any enrollment PRs created in target repos.
- Installer scaffold: the `WorkflowsLayer` deploys content from an embedded scaffold (`internal/scaffold/`), keeping deployable files as real files under version control rather than Go string constants.

**Open questions:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,24 @@ install of these layers:
| Path | Layer responsible |
|------|-------------------|
| `config.yaml` | `ConfigRepoLayer` |
| `.github/workflows/agent.yaml` | `WorkflowsLayer` |
| `.github/workflows/repo-onboard.yaml` | `WorkflowsLayer` |
| `.github/workflows/triage.yml` | `WorkflowsLayer` |
| `.github/workflows/code.yml` | `WorkflowsLayer` |
| `.github/workflows/review.yml` | `WorkflowsLayer` |
| `.github/workflows/repo-maintenance.yml` | `WorkflowsLayer` |
| `.github/actions/fullsend/action.yml` | `WorkflowsLayer` |
| `.github/scripts/setup-agent-env.sh` | `WorkflowsLayer` |
| `agents/triage.md` | `WorkflowsLayer` |
| `env/gcp-vertex.env` | `WorkflowsLayer` |
| `env/triage.env` | `WorkflowsLayer` |
| `harness/triage.yaml` | `WorkflowsLayer` |
| `policies/triage.yaml` | `WorkflowsLayer` |
| `scripts/validate-triage.sh` | `WorkflowsLayer` |
| `scripts/reconcile-repos.sh` | `WorkflowsLayer` |
| `templates/shim-workflow.yaml` | `WorkflowsLayer` |
| `CODEOWNERS` | `WorkflowsLayer` |

Write order for workflow-related paths: `agent.yaml`, then `repo-onboard.yaml`,
then `CODEOWNERS` (CODEOWNERS failure is non-fatal in the implementation).
Write order: all scaffold files from `internal/scaffold/fullsend-repo/` in
filesystem walk order, then `CODEOWNERS` last (CODEOWNERS failure is non-fatal).

## 3. Per-path requirements

Expand All @@ -35,19 +47,70 @@ then `CODEOWNERS` (CODEOWNERS failure is non-fatal in the implementation).
(this SPEC only requires that the file exists as the tracked carrier for
org configuration).

### 3.2 `.github/workflows/agent.yaml`
### 3.2 `.github/workflows/triage.yml`

- **Contents:** exactly the document in
[`files/agent-dispatch-v1.yaml`](files/agent-dispatch-v1.yaml) (byte-for-byte
normative snapshot for v1).
- Triage workflow triggered via `workflow_dispatch` with `event_type`,
`source_repo`, `event_payload` inputs.

### 3.3 `.github/workflows/repo-onboard.yaml`
### 3.3 `.github/workflows/code.yml`

- **Contents:** exactly the document in
[`files/repo-onboard-v1.yaml`](files/repo-onboard-v1.yaml) (byte-for-byte
normative snapshot for v1).
- Code workflow, same dispatch pattern as triage.

### 3.4 `CODEOWNERS`
### 3.4 `.github/workflows/review.yml`

- Review workflow, same dispatch pattern as triage.

### 3.5 `.github/workflows/repo-maintenance.yml`

- Reconciles enrollment shims in target repos when `config.yaml` changes.

### 3.6 `.github/actions/fullsend/action.yml`

- Composite action: installs the fullsend CLI and runs the agent.

### 3.7 `.github/scripts/setup-agent-env.sh`

- Env prefix stripping helper sourced by per-role workflows.

### 3.8 `agents/triage.md`

- Agent instructions for the triage role.

### 3.9 `env/gcp-vertex.env`

- Environment variables for GCP Vertex AI inference.

### 3.10 `env/triage.env`

- Environment variables specific to the triage role.

### 3.11 `harness/triage.yaml`

- Harness configuration for the triage role.

### 3.12 `policies/triage.yaml`

- Policy definitions for the triage role.

### 3.13 `scripts/validate-triage.sh`

- Validation script for triage role output.

### 3.14 `scripts/reconcile-repos.sh`

- Shell script that reconciles enrollment shims in target repos. Called by
`repo-maintenance.yml`. Uses `gh` CLI and `yq` to read `config.yaml`.
For enabled repos: creates branches, writes shim workflows, and opens
enrollment PRs. For disabled repos: creates branches, deletes shim
workflows (via GitHub Contents API DELETE with blob SHA), and opens
removal PRs. Closes stale cross-direction PRs in both cases.

### 3.15 `templates/shim-workflow.yaml`

- The shim workflow template used by `scripts/reconcile-repos.sh` to write shim
workflows to target repos during enrollment and verify content during updates.

### 3.16 `CODEOWNERS`

- **Purpose:** grant the installing human ownership of all paths in the
configuration repo.
Expand All @@ -66,9 +129,10 @@ includes `@` before the login as shown).
## 4. Relationship to implementation

The reference implementation lives in `internal/layers/configrepo.go` and
`internal/layers/workflows.go`. If implementation and this SPEC diverge, this
SPEC is normative for **v1** tracked layout and file bodies (except
`config.yaml` body per ADR 0011).
`internal/layers/workflows.go`. The `WorkflowsLayer` deploys content from the
embedded scaffold at `internal/scaffold/fullsend-repo/`. If implementation and
this SPEC diverge, this SPEC is normative for **v1** tracked layout and file
bodies (except `config.yaml` body per ADR 0011).

## 5. Out of scope (not Git-tracked in `.fullsend`)

Expand Down

This file was deleted.

This file was deleted.

Loading
Loading