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
11 changes: 11 additions & 0 deletions actions/setup/js/replace_label.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ const main = createCountGatedHandler({

const updatedLabelNames = (updatedLabels || []).map((/** @param {any} l */ l) => l.name || "").filter(Boolean);

if (!updatedLabelNames.includes(labelToAdd)) {
const error = `replace_label: label_to_add ${JSON.stringify(labelToAdd)} not found in POST-setLabels response`;
core.error(error);
return { success: false, error };
}
if (labelToRemoveIsPresent && labelToRemove !== labelToAdd && updatedLabelNames.includes(labelToRemove)) {
const error = `replace_label: label_to_remove ${JSON.stringify(labelToRemove)} still present after setLabels call`;
core.error(error);
return { success: false, error };
}

core.info(`Successfully replaced label "${labelToRemove}" → "${labelToAdd}" on ${contextType} #${itemNumber} in ${itemRepo}`);
core.info(`Updated labels: ${JSON.stringify(updatedLabelNames)}`);

Expand Down
30 changes: 30 additions & 0 deletions actions/setup/js/replace_label.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,36 @@ describe("replace_label", () => {
expect(result.success).toBe(false);
});

it("should reject a successful setLabels response that omits label_to_add", async () => {
mockGithub.rest.issues.setLabels = async () => ({
data: [{ name: "bug" }],
});

const handler = await main({});
const result = await handler({ label_to_remove: "in-progress", label_to_add: "done" }, {});

expect(result).toEqual({
success: false,
error: 'replace_label: label_to_add "done" not found in POST-setLabels response',
});
expect(mockCore.errors).toContain(result.error);
});

it("should reject a successful setLabels response that retains label_to_remove", async () => {
mockGithub.rest.issues.setLabels = async () => ({
data: [{ name: "in-progress" }, { name: "bug" }, { name: "done" }],
});

const handler = await main({});
const result = await handler({ label_to_remove: "in-progress", label_to_add: "done" }, {});

expect(result).toEqual({
success: false,
error: 'replace_label: label_to_remove "in-progress" still present after setLabels call',
});
expect(mockCore.errors).toContain(result.error);
});

describe("allowed-transitions", () => {
it("should allow a transition that is in the allowed-transitions list", async () => {
const handler = await main({
Expand Down
11 changes: 11 additions & 0 deletions specs/intent-attribution-compliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ F7_SingleSourcePerRecord(a) ≜
Resolve(a) is attributed to exactly one source
```

### Structure

`PolicyCompiler` produces an `ExecutionPolicy` that carries the governance
decision (`autonomy`, tool restrictions, `write_scope`, required checks,
approval, auto-merge, attempts, and matched rule IDs). It does not populate
CLI outcome-report fields directly. The outcome evaluator records
`objective_value` and `objective_labels` from objective mapping and
`traced_root_url` from the resolved artifact relationship; its
`attribution_status` and `attribution_source` preserve the attribution
context that was supplied to policy compilation.
Comment on lines +95 to +97

## Behavioral Coverage Map

| Predicate / Invariant | Test Function | Description |
Expand Down
13 changes: 13 additions & 0 deletions specs/otel-observability-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,16 @@ Job finalization SHOULD finish functional work, record result attributes and eve

When an additive pipeline root span is emitted, it SHOULD end only after the workflow result and all known job results are available.

### Safeguards

Observability is fail-closed with respect to telemetry correctness and
secrets: export failures, partial endpoint fan-out failures, and shutdown
timeouts MUST be recorded as bounded diagnostics and MUST NOT be reported as
successful delivery. They MUST NOT discard successful endpoint deliveries,
delete local mirror data, expose exporter credentials, or interrupt already
completed functional workflow work. Finalization MUST write eligible mirror
records and end known spans before its bounded exporter flush.

---

## 17. Compliance Testing
Expand Down Expand Up @@ -897,6 +907,8 @@ The following implementation areas are authoritative for version 0.4.0 compatibi
| Frontmatter schema | `pkg/parser/schemas/main_workflow_schema.json`, `pkg/parser/schema_test.go` |
| Compiler normalization and env injection | `pkg/workflow/observability_otlp.go`, `pkg/workflow/observability_otlp_test.go`, `pkg/workflow/safe_output_helpers_test.go` |
| Gateway credential scoping | `pkg/workflow/mcp_renderer.go`, `pkg/workflow/mcp_setup_generator.go`, `pkg/workflow/mcp_renderer_test.go` |
| MCP access-control fixture contract | `specs/github-mcp-access-control-compliance/README.md` |
| Replace-label fixture contract | `specs/replace-label-compliance/README.md` |
Comment on lines +910 to +911
| Runtime setup/conclusion spans and JSONL mirror | `actions/setup/js/send_otlp_span.cjs`, `actions/setup/js/send_otlp_span.test.cjs`, `actions/setup/js/otel_contract.test.cjs` |
| Header and attribute masking | `actions/setup/sh/mask_otlp_headers.sh`, `actions/setup/sh/mask_otlp_attributes.sh`, `pkg/workflow/observability_otlp_mask_script_test.go` |
| Local validation target | `Makefile` target `validate-otel-contract` |
Expand Down Expand Up @@ -949,6 +961,7 @@ context is added to outcome spans or links.
- **Clarified**: A versioned mirror envelope may be added only as an additive format; `/tmp/gh-aw/otel.jsonl` remains raw OTLP/JSON lines for compatibility.
- **Added**: Metric cardinality, privacy, redaction, and secret-handling guidance while preserving existing artifacts and query surfaces.
- **Added**: Inlined compatibility validation requirements, optional extension tests, and the implementation map so this document is self-contained.
- **Added**: Consolidated fail-closed safeguards for export, endpoint fan-out, and shutdown handling.
- **See also**: `specs/safe-output-outcome-evaluation.md` (Change Log, Version 1.0.1) for aligned outcome-taxonomy and provenance rules.

### Version 0.3.0 (Working Draft, June 15, 2026)
Expand Down
9 changes: 4 additions & 5 deletions specs/replace-label-compliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Evaluation order is modeled as: blocked check → allowlist check → gates
| Edge: self-transition not implicit | `TestFormalTransitionEdge_SelfTransitionRejectedWhenNotListed` | `from == to` is not implicitly allowed unless explicitly listed |
| Edge: duplicate transition entries | `TestFormalTransitionEdge_DuplicateTransitionEntriesIdempotent` | Duplicate entries in the list don't change the allow/deny decision |

Coverage parity check (2026-08-03): verified Behavioral Coverage Map entries
Coverage parity check (2026-08-05): verified Behavioral Coverage Map entries
are implemented in:

- `pkg/workflow/replace_label_formal_test.go`
Expand Down Expand Up @@ -137,7 +137,6 @@ The suite runs fully in-process under Go test, reads the fixture YAML files in
this directory, and does not require a JavaScript runtime to validate the
formal predicates.

The RL-057/RL-058/RL-059 post-`setLabels` checks are currently formalized in
the Go suite via a formal helper stub and document a spec/implementation gap:
`actions/setup/js/replace_label.cjs` does not yet enforce these predicates on
HTTP 200 responses.
The RL-057/RL-058/RL-059 post-`setLabels` checks are enforced by
`actions/setup/js/replace_label.cjs` and covered by
`actions/setup/js/replace_label.test.cjs`.
Loading