Skip to content
Closed
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
4 changes: 4 additions & 0 deletions pkg/logger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ DEBUG=* gh aw compile workflow.md 2>&1 | tee output.log
- `-pattern` - Excludes loggers matching the pattern (takes precedence)
- `pattern1,pattern2` - Multiple patterns separated by commas

## Sync Notes

- When JSONL event field names, per-turn token reporting format, or stderr logging semantics used by AW harness observability change, update [`specs/aw-harness.md` §8.5](../../specs/aw-harness.md#85-extension-5-observability) and the harness sync table in the same pull request.

## Design Decisions

### Logger Enabled State
Expand Down
39 changes: 39 additions & 0 deletions scratchpad/github-mcp-access-control-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ This document is governed by the GitHub Agentic Workflows project specifications
9. [Security Model](#9-security-model)
10. [Integration with MCP Gateway](#10-integration-with-mcp-gateway)
11. [Compliance Testing](#11-compliance-testing)
12. [Norms](#norms)
13. [Entities](#entities)

---

Expand Down Expand Up @@ -818,6 +820,26 @@ approval-labels:
Warning: approval-labels is an empty array. Omit the field entirely to disable label-based approval.
```

#### 4.4.8 Precedence and Conflict Resolution (Analysis)

When `repos`, `roles`, and `blocked-users` are configured together, implementations MUST evaluate them as independent guards in the documented order and fail closed on the first guard that fails.

- `repos` scope is evaluated first as part of repository authorization. A repository outside the allowlist MUST be denied before any author-based checks are considered.
- `roles` filtering is evaluated after repository matching. A role mismatch MUST deny access even when the author is not blocked.
- `blocked-users` is evaluated in integrity management after repository and role checks. A blocked author MUST still be denied even when repository and role checks pass.

**Worked example**:

```yaml
repos: ["github/*"]
roles: ["write", "admin"]
blocked-users: ["external-bot"]
```

- Request A: `repository=octocat/demo`, `user_role=admin`, `user_login=external-bot` → deny at `repos` guard (`-32002`) because `octocat/demo` is outside `github/*`.
- Request B: `repository=github/gh-aw`, `user_role=read`, `user_login=external-bot` → deny at `roles` guard (`-32003`) because role is insufficient.
- Request C: `repository=github/gh-aw`, `user_role=write`, `user_login=external-bot` → deny at `blocked-users` guard (`-32005`) because repository and role checks pass first.

### 4.5 Relationship Between Tool Selection and Access Control

The GitHub MCP server configuration combines tool selection (`toolsets` and `tools`) with access control (`repos`, `roles`, `private-repos`) and integrity-level management (`min-integrity`, `blocked-users`, `approval-labels`). These mechanisms operate independently but complement each other:
Expand Down Expand Up @@ -2158,6 +2180,7 @@ The following fixture files in [`specs/github-mcp-access-control-compliance/`](.
| [`private-repo-block.yaml`](../../specs/github-mcp-access-control-compliance/private-repo-block.yaml) | `private-repos: false` blocks private repo; allows public repo | T-GH-024, T-GH-025, T-GH-026 |
| [`integrity-level-block.yaml`](../../specs/github-mcp-access-control-compliance/integrity-level-block.yaml) | `min-integrity` allows content at/above threshold; blocks content below | T-GH-051, T-GH-052, T-GH-054 |
| [`combined-blocked-integrity.yaml`](../../specs/github-mcp-access-control-compliance/combined-blocked-integrity.yaml) | Combined P5+P6: blocked user denied with `-32005` even when P6 would also fail; non-blocked user with sufficient integrity allowed | T-GH-091, T-GH-092, T-GH-093 |
| [`blocked-users-min-integrity-extension-fields.yaml`](../../specs/github-mcp-access-control-compliance/blocked-users-min-integrity-extension-fields.yaml) | Direct §4.4 extension-field fixture: `min-integrity` threshold denial and `blocked-users` unconditional denial semantics | T-GH-094, T-GH-095 |

See [`specs/github-mcp-access-control-compliance/README.md`](../../specs/github-mcp-access-control-compliance/README.md) for fixture schema documentation and instructions for adding new scenarios.

Expand Down Expand Up @@ -2673,6 +2696,22 @@ GitHub API rate limits apply to:

---

## Norms

- **Default-deny guard posture.** Implementations MUST treat each configured guard (`repos`, `roles`, `private-repos`, `blocked-users`, `min-integrity`) as independently denying access when it fails; access is allowed only when all enabled guards pass.
- **Repository pattern matching is case-sensitive.** `owner/repo` comparisons in `repos` matching SHOULD be evaluated as exact string comparisons after canonical owner/repo extraction. Implementations MUST NOT silently normalize case in a way that broadens access beyond the configured patterns.
- **Deprecated alias handling.** Workflow authors SHOULD use `allowed-repos` in frontmatter. The `repos` frontmatter alias remains deprecated and MUST NOT be preferred over `allowed-repos` when both are present.

## Entities

| Entity | Description | Defined in |
|---|---|---|
| `GitHubToolConfig` | Gateway-facing configuration object under `tools.github`, including repository, role, visibility, and integrity controls. | §4.1, §4.4 |
| `GitHubReposScope` | Repository allowlist pattern set (`owner/repo`, `owner/*`, `*/repo`, `*/*`). | §4.4.1, §5.1 |
| `GitHubRoles` | Explicit role allowlist over GitHub repository roles (`read`, `triage`, `write`, `maintain`, `admin`). | §4.4.2, §6 |
| `GitHubIntegrityLevel` | Ordered integrity lattice (`none` < `unapproved` < `approved` < `merged`) used by threshold checks. | §4.4.4, §4.6 |
| `AccessRequest` | Runtime authorization input tuple containing repository identity, actor, repository visibility, and content integrity. | §4.5, §8.5 |

## Sync Notes

This section maps all seven §4.4 access control extension fields to their implementation files, enabling traceability between specification and code.
Expand Down
34 changes: 31 additions & 3 deletions scratchpad/safe-outputs-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ This specification is governed by the GitHub Next team and follows semantic vers
6. [GitHub Operations](#6-github-operations)
- [6.4 update-discussion Operation](#64-update-discussion-operation)
7. [Compliance Testing](#7-compliance-testing)
8. [Appendices](#appendices)
9. [References](#references)
10. [Change Log](#change-log)
8. [Entities](#entities)
9. [Appendices](#appendices)
10. [References](#references)
11. [Change Log](#change-log)

---

Expand Down Expand Up @@ -664,6 +665,23 @@ The noop handler MUST:

GitHub operations enable AI agents to interact with GitHub resources. These operations are separated from builtin tools because they are specific to GitHub's platform and require specialized permissions and handling.

### 6.0 Files Modified (Implementation Checklist)

When implementing or updating GitHub operations in this section, maintainers SHOULD verify the following implementation surfaces in the same change:

1. **`pkg/workflow/safe_outputs_tools.go`**
- Operation-level tool definitions and schema wiring
2. **`pkg/workflow/safe_outputs_validation.go`**
- Operation request validation and guardrail enforcement
3. **`pkg/workflow/safe_outputs_handler_registry.go`**
- Operation-to-handler registration and dispatch routing
4. **`pkg/workflow/safe_outputs_jobs.go`**
- Execution-job orchestration for write operations
5. **`pkg/workflow/safe_outputs_permissions.go`**
- Per-operation GitHub permission declarations
6. **`pkg/workflow/safe_outputs_steps.go`**
- Job step generation and execution flow mapping

### 6.1 Operation Categories

#### 6.1.1 Issues & Discussions
Expand Down Expand Up @@ -1186,6 +1204,16 @@ The system does NOT protect against:

---

## Entities

| Entity | Description | Defined in |
|---|---|---|
| `SafeOutputsConfig` | Top-level `safe-outputs` frontmatter object that enables builtin tools, GitHub operations, and optional custom jobs. | §3.2 |
| `SafeOutputToolRegistration` | MCP tool registration record containing tool `name`, `description`, `inputSchema`, and runtime `handler`. | §3.3.2 |
| `SafeOutputEnvelope` | NDJSON line record emitted by Layer 2 with at least `type` and operation payload fields. | §3.3.4 |
| `ValidationGuardrailConfig` | Guardrail policy bundle for schema validation, max-count limits, sanitization, target validation, and cross-repo checks. | §3.4 |
| `ExecutionHandlerJob` | Isolated GitHub Actions job definition that consumes validated output and executes write-side effects. | §3.5 |

## References

### Normative References
Expand Down
21 changes: 21 additions & 0 deletions specs/aw-harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ This is an internal design specification for the GitHub gh-aw project. It is not
12. [Compliance Tests](#12-compliance-tests)
13. [Privacy Considerations](#13-privacy-considerations)
14. [References](#14-references)
15. [Entities](#entities)

---

Expand Down Expand Up @@ -517,6 +518,16 @@ A conforming implementation **MUST** execute the workflow as follows:
4. After the session completes (success or failure), the implementation **MUST** call `session.dispose()`.
5. If the budget gate has been triggered (via the cost-tracker extension), the implementation **MUST** exit with code `1`.

### 7.1.1 Budget-Exceeded Failure Mode

If `harness.budget` is exceeded while a turn is in progress, the harness **MUST** fail closed for that session:

1. The cost-tracker extension **MUST** request termination (`ctx.agent.abort()`) as soon as the configured hard limit is crossed (see [Section 8.3](#83-extension-3-steering-resource-pressure)).
2. The harness **MUST** allow the current turn lifecycle to unwind and then **MUST NOT** start another turn.
3. The harness **MUST** emit a budget-exceeded signal in stderr/summary output and exit with code `1` (per [Section 5.3](#53-exit-codes)).

This behavior ensures deterministic shutdown without permitting additional tool calls after budget exhaustion.

### 7.2 Execution Summary

```
Expand Down Expand Up @@ -1248,6 +1259,15 @@ GitHub Agentic Workflows — the gh-aw CLI extension that compiles Markdown work

---

## Entities

| Entity | Description | Defined in |
|---|---|---|
| `HarnessBudgetConfig` (`harness.budget`) | Budget controls for hard token/credit ceilings and budget-triggered termination behavior. | §6.1.1, §7.1.1, §8.2 |
| `HarnessContextConfig` (`harness.context`) | Context loading and context-window management settings consumed before session execution. | §6.1.2, §6.4 |
| `HarnessSteeringConfig` (`harness.steering`) | Time-pressure and budget-pressure steering thresholds used by runtime extensions. | §6.1.3, §8.2, §8.3 |
| `HarnessExtensionRef` (`harness.extensions`) | Ordered user extension references that load after built-in extensions, with optional required/fail-open behavior. | §6.1.4, §8.6 |

## Sync Notes

This section maps normative spec sections to their primary implementation files and directories in the `github/gh-aw` repository. Maintainers **SHOULD** keep this table updated whenever implementation files are added, renamed, or removed.
Expand All @@ -1259,4 +1279,5 @@ This section maps normative spec sections to their primary implementation files
| §10 Build and Deployment; §10.1 esbuild configuration | `actions/setup/js/` (directory); `package.json` build scripts in `github/gh-aw` | JavaScript build toolchain. The harness is compiled with esbuild; build configuration and bundle output paths are tracked here. |
| §9 Model Resolution; §11.1 General Security Requirements (token/credential handling) | `pkg/workflow/` (Go compiler — `aw_engine.go` or equivalent) | The `engine: aw` compilation path in Go generates the `config.json` that specifies the model, provider credentials, and feature flags consumed by the harness at runtime. |
| §11.2 Safeguards; §11.4 Degraded Mode & Safeguards | `actions/setup/js/aw_harness.cjs` | Budget-gating, observability-failure recovery, and fail-secure exit-code enforcement are all implemented inside the harness. |
| §8.5 Extension 5: Observability | `actions/setup/js/aw_harness.cjs`; `pkg/logger/README.md` | Keep JSONL event field names and logging expectations synchronized; logger package docs SHOULD link back to this section when event schema semantics change. |
| §12 Compliance Tests (T-AW-001 through T-AW-007) | `pkg/cli/workflows/` (integration test workflows); `actions/setup/js/*.test.cjs` (unit tests) | Harness lifecycle integration tests live in `pkg/cli/workflows/`. Unit-level tests for harness helpers reside alongside the JavaScript source. |
8 changes: 5 additions & 3 deletions specs/awf-config-sources-compliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ The following test IDs cover the `DriftRecord` schema and its usage requirements

## Spec Reference

- **Specification**: `specs/awf-config-sources-spec.md`
- **Defining section**: §6.5 — DriftRecord Entity Schema
- **Related sections**: §6.2 (Drift Detection Procedure), §5 (Conformance Requirements CR-05, CR-06)
- **Specification**: [`specs/awf-config-sources-spec.md`](../awf-config-sources-spec.md)
- **DriftRecord entity schema**: [§7.5 — DriftRecord Entity Schema](../awf-config-sources-spec.md#75-driftrecord-entity-schema)
- **Conformance requirements**: [§6 — Conformance Requirements](../awf-config-sources-spec.md#6-conformance-requirements) (CR-05, CR-06)
- **Drift detection procedure**: [§7.2 — Step-by-Step Procedure](../awf-config-sources-spec.md#72-step-by-step-procedure)
- **Canonical source set**: [§2 — Canonical sources (gh-aw-firewall)](../awf-config-sources-spec.md#2-canonical-sources-gh-aw-firewall)

---

Expand Down
1 change: 1 addition & 0 deletions specs/github-mcp-access-control-compliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ The denial code is selected by the first failing guard in the evaluation order a
| `integrity-level-block.yaml` | `min-integrity: approved` blocks content below the threshold | T-GH-051, T-GH-052 |
| `combined-filter-allow.yaml` | All access-control conditions must be jointly satisfied | T-GH-081, T-GH-082, T-GH-083 |
| `combined-blocked-integrity.yaml` | `blocked-users` (P5) and `min-integrity` (P6) evaluated simultaneously; P5 fires first when both fail | T-GH-091, T-GH-092, T-GH-093 |
| `blocked-users-min-integrity-extension-fields.yaml` | §4.4.4/§4.4.5 extension-field conformance for threshold and unconditional block behavior | T-GH-094, T-GH-095 |

## Fixture Schema

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# blocked-users + min-integrity Extension Fields — Compliance Fixture
# Tests: T-GH-094, T-GH-095
# Spec: §4.4.4 min-integrity, §4.4.5 blocked-users

fixture_id: "blocked-users-min-integrity-extension-fields"
description: >
This fixture binds the §4.4 extension-field definitions to runtime behavior.
`min-integrity` MUST reject content below the configured threshold, and
`blocked-users` MUST deny listed users unconditionally before integrity checks.

spec_refs:
- "§4.4.4 — min-integrity defines minimum accepted integrity"
- "§4.4.5 — blocked-users are unconditionally denied"
- "§4.4.8 — precedence: blocked-users evaluated after repo/role checks and before integrity threshold"

scenarios:
- scenario_id: "blocked-users-min-integrity-extension-fields-A"
description: "Non-blocked user below min-integrity is denied with -32006"
input:
tool_config:
repos:
- "github/gh-aw"
roles:
- "write"
min-integrity: "approved"
blocked-users:
- "external-bot"
request:
repository: "github/gh-aw"
user_login: "trusted-contributor"
user_role: "write"
is_private: true
content_integrity: "unapproved"
expected:
decision: deny
error_code: -32006
reason: "content integrity below minimum required level"

- scenario_id: "blocked-users-min-integrity-extension-fields-B"
description: "Blocked user is denied with -32005 even when integrity would otherwise pass"
input:
tool_config:
repos:
- "github/gh-aw"
roles:
- "write"
min-integrity: "approved"
blocked-users:
- "external-bot"
request:
repository: "github/gh-aw"
user_login: "external-bot"
user_role: "write"
is_private: true
content_integrity: "merged"
expected:
decision: deny
error_code: -32005
reason: "user is blocked"