From d3830c00229ec4d61f94197f29f3f38f6d2cc96a Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer Date: Wed, 17 Jun 2026 04:55:08 +0200 Subject: [PATCH 1/9] Improve outcome intent attribution --- .../setup/js/assign_agent_helpers.test.cjs | 5 +- pkg/cli/outcome_eval.go | 97 +- pkg/cli/outcome_eval_test.go | 62 + pkg/intent/resolver.go | 155 +++ pkg/intent/resolver_test.go | 118 ++ pkg/workflow/action_resolver.go | 16 +- specs/intent-attribution-agent-governance.md | 1218 +++++++++++++++++ .../objective-mapping-portfolio-reporting.md | 571 -------- 8 files changed, 1626 insertions(+), 616 deletions(-) create mode 100644 pkg/intent/resolver.go create mode 100644 pkg/intent/resolver_test.go create mode 100644 specs/intent-attribution-agent-governance.md delete mode 100644 specs/objective-mapping-portfolio-reporting.md diff --git a/actions/setup/js/assign_agent_helpers.test.cjs b/actions/setup/js/assign_agent_helpers.test.cjs index cefd89b2d63..b8e7f7875a0 100644 --- a/actions/setup/js/assign_agent_helpers.test.cjs +++ b/actions/setup/js/assign_agent_helpers.test.cjs @@ -17,8 +17,9 @@ const mockGithub = { globalThis.core = mockCore; globalThis.github = mockGithub; -const { AGENT_LOGIN_NAMES, getAgentName, getAvailableAgentLogins, findAgent, getIssueDetails, getPullRequestDetails, assignAgentToIssue, generatePermissionErrorSummary, assignAgentToIssueByName } = - await import("./assign_agent_helpers.cjs"); +const { AGENT_LOGIN_NAMES, getAgentName, getAvailableAgentLogins, findAgent, getIssueDetails, getPullRequestDetails, assignAgentToIssue, generatePermissionErrorSummary, assignAgentToIssueByName } = await import( + "./assign_agent_helpers.cjs" +); describe("assign_agent_helpers.cjs", () => { beforeEach(() => { diff --git a/pkg/cli/outcome_eval.go b/pkg/cli/outcome_eval.go index 707d9f3e5e3..4a0162fa060 100644 --- a/pkg/cli/outcome_eval.go +++ b/pkg/cli/outcome_eval.go @@ -8,6 +8,7 @@ import ( "time" "github.com/github/gh-aw/pkg/github" + "github.com/github/gh-aw/pkg/intent" "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/workflow" ) @@ -37,6 +38,8 @@ type OutcomeReport struct { ObjectURL string `json:"object_url,omitempty" console:"header:URL,omitempty"` ObjectNumber int `json:"object_number,omitempty" console:"header:#,omitempty"` TracedRootURL string `json:"traced_root_url,omitempty" console:"-"` + AttributionStatus string `json:"attribution_status,omitempty" console:"-"` + AttributionSource string `json:"attribution_source,omitempty" console:"-"` Repo string `json:"repo,omitempty" console:"header:Repo,omitempty"` Result OutcomeResult `json:"result" console:"header:Outcome"` Detail string `json:"detail,omitempty" console:"header:Detail,omitempty"` @@ -402,16 +405,18 @@ func enrichOutcomeWithObjectiveValue(report *OutcomeReport, repo string, mapping outcomeEvalLog.Printf("Computing objective value: type=%s, repo=%s, number=%d", report.Type, repo, num) - root, err := traceOutcomeRoot(*report, repo) + resolvedIntent, err := resolveOutcomeIntent(*report, repo, mapping) if err != nil { outcomeEvalLog.Printf("Could not trace root for objective value computation: %v", err) return } - report.TracedRootURL = root.URL + report.AttributionStatus = string(resolvedIntent.Status) + report.AttributionSource = string(resolvedIntent.Source) + report.TracedRootURL = resolvedIntent.RootURL - labelNames := root.Labels + labelNames := resolvedIntent.Labels if len(labelNames) > 0 { - outcomeEvalLog.Printf("Fetched root labels for %s#%d: root=%s labels=%v", repo, num, root.URL, labelNames) + outcomeEvalLog.Printf("Fetched root labels for %s#%d: root=%s labels=%v", repo, num, resolvedIntent.RootURL, labelNames) } // Compute objective value @@ -423,17 +428,18 @@ func enrichOutcomeWithObjectiveValue(report *OutcomeReport, repo string, mapping outcomeEvalLog.Printf("Computed objective value for %s#%d: value=%d, labels=%v", repo, num, objectiveValue, objectiveLabels) } -type tracedOutcomeRoot struct { - URL string - Number int - Labels []string -} +func resolveOutcomeIntent(report OutcomeReport, repo string, mapping *github.ObjectiveMapping) (intent.IntentRecord, error) { + resolver := intent.Resolver{ + ResolverVersion: "outcome-eval-v1", + MatchLabels: func(labels []string) []string { + return mapping.GetObjectiveLabels(labels) + }, + } -func traceOutcomeRoot(report OutcomeReport, repo string) (tracedOutcomeRoot, error) { if isPullRequestOutcomeType(report.Type) { - root, err := tracePullRequestRoot(report.ObjectNumber, repo) - if err == nil && root.Number > 0 { - return root, nil + prIntent, err := resolvePullRequestIntent(report, repo, resolver) + if err == nil { + return prIntent, nil } if err != nil { outcomeEvalLog.Printf("Falling back to direct labels after PR root trace failure: %v", err) @@ -442,13 +448,9 @@ func traceOutcomeRoot(report OutcomeReport, repo string) (tracedOutcomeRoot, err labels, err := objectiveMappingGHAPIGetArray(fmt.Sprintf("issues/%d/labels", report.ObjectNumber), repo) if err != nil { - return tracedOutcomeRoot{}, err + return intent.IntentRecord{}, err } - return tracedOutcomeRoot{ - URL: report.ObjectURL, - Number: report.ObjectNumber, - Labels: labelsToStringsFromMaps(labels), - }, nil + return resolver.ResolveIssue("", report.ObjectURL, labelsToStringsFromMaps(labels)), nil } func isPullRequestOutcomeType(outcomeType string) bool { @@ -462,18 +464,29 @@ func isPullRequestOutcomeType(outcomeType string) bool { } } -func tracePullRequestRoot(prNumber int, repo string) (tracedOutcomeRoot, error) { +func resolvePullRequestIntent(report OutcomeReport, repo string, resolver intent.Resolver) (intent.IntentRecord, error) { + prData, err := loadPullRequestIntentData(report, repo) + if err != nil { + return intent.IntentRecord{}, err + } + return resolver.ResolvePullRequest(prData), nil +} + +func loadPullRequestIntentData(report OutcomeReport, repo string) (intent.PullRequestData, error) { + prNumber := report.ObjectNumber ownerRepo, _ := normalizeRepoForAPI(repo) owner, name, found := strings.Cut(ownerRepo, "/") if !found || owner == "" || name == "" { - return tracedOutcomeRoot{}, fmt.Errorf("invalid repo for root tracing: %s", repo) + return intent.PullRequestData{}, fmt.Errorf("invalid repo for root tracing: %s", repo) } query := fmt.Sprintf(`query { repository(owner: "%s", name: "%s") { pullRequest(number: %d) { + id closingIssuesReferences(first: 10) { nodes { + id number url labels(first: 20) { @@ -491,30 +504,44 @@ func tracePullRequestRoot(prNumber int, repo string) (tracedOutcomeRoot, error) result, err := objectiveMappingGHAPIGraphQL(query, repo) if err != nil { - return tracedOutcomeRoot{}, err + return intent.PullRequestData{}, err } data, _ := result["data"].(map[string]any) repository, _ := data["repository"].(map[string]any) pullRequest, _ := repository["pullRequest"].(map[string]any) + prData := intent.PullRequestData{URL: report.ObjectURL} + if nodeID, ok := pullRequest["id"].(string); ok { + prData.NodeID = nodeID + } closingRefs, _ := pullRequest["closingIssuesReferences"].(map[string]any) nodes, _ := closingRefs["nodes"].([]any) if len(nodes) == 0 { - return tracedOutcomeRoot{}, fmt.Errorf("no closing issues found for PR #%d", prNumber) - } - firstNode, _ := nodes[0].(map[string]any) - root := tracedOutcomeRoot{} - if url, ok := firstNode["url"].(string); ok { - root.URL = url - } - if number, ok := firstNode["number"].(float64); ok { - root.Number = int(number) + labels, labelErr := objectiveMappingGHAPIGetArray(fmt.Sprintf("issues/%d/labels", report.ObjectNumber), repo) + if labelErr == nil { + prData.Labels = labelsToStringsFromMaps(labels) + } + return prData, nil } - if labels, ok := firstNode["labels"].(map[string]any); ok { - if labelNodes, ok := labels["nodes"].([]any); ok { - root.Labels = labelsToStringsFromNodes(labelNodes) + + prData.ClosingIssues = make([]intent.RootReference, 0, len(nodes)) + for _, node := range nodes { + rootNode, _ := node.(map[string]any) + root := intent.RootReference{Type: "issue"} + if nodeID, ok := rootNode["id"].(string); ok { + root.NodeID = nodeID } + if url, ok := rootNode["url"].(string); ok { + root.URL = url + } + if labels, ok := rootNode["labels"].(map[string]any); ok { + if labelNodes, ok := labels["nodes"].([]any); ok { + root.Labels = labelsToStringsFromNodes(labelNodes) + } + } + prData.ClosingIssues = append(prData.ClosingIssues, root) } - return root, nil + + return prData, nil } func labelsToStringsFromNodes(nodes []any) []string { diff --git a/pkg/cli/outcome_eval_test.go b/pkg/cli/outcome_eval_test.go index 7d6c7217f97..c89b88b1a69 100644 --- a/pkg/cli/outcome_eval_test.go +++ b/pkg/cli/outcome_eval_test.go @@ -220,9 +220,11 @@ func TestEnrichOutcomeWithObjectiveValue_TracesPullRequestToRootIssue(t *testing "data": map[string]any{ "repository": map[string]any{ "pullRequest": map[string]any{ + "id": "PR_kwDOAAABCD4", "closingIssuesReferences": map[string]any{ "nodes": []any{ map[string]any{ + "id": "I_kwDOAAABCQ4", "number": float64(1234), "url": "https://github.com/owner/repo/issues/1234", "labels": map[string]any{"nodes": []any{ @@ -253,6 +255,8 @@ func TestEnrichOutcomeWithObjectiveValue_TracesPullRequestToRootIssue(t *testing assert.Equal(t, 90, report.ObjectiveValue) assert.Equal(t, []string{"agentic-campaign", "security"}, report.ObjectiveLabels) assert.Equal(t, "https://github.com/owner/repo/issues/1234", report.TracedRootURL) + assert.Equal(t, "mapped", report.AttributionStatus) + assert.Equal(t, "closing_issue", report.AttributionSource) } func TestEnrichOutcomeWithObjectiveValue_FallsBackToDirectLabels(t *testing.T) { @@ -278,6 +282,64 @@ func TestEnrichOutcomeWithObjectiveValue_FallsBackToDirectLabels(t *testing.T) { assert.Equal(t, 70, report.ObjectiveValue) assert.Equal(t, []string{"automation", "testing"}, report.ObjectiveLabels) assert.Equal(t, "https://github.com/owner/repo/issues/42", report.TracedRootURL) + assert.Equal(t, "mapped", report.AttributionStatus) + assert.Equal(t, "issue_labels", report.AttributionSource) +} + +func TestEnrichOutcomeWithObjectiveValue_MultipleClosingIssuesRemainAmbiguous(t *testing.T) { + oldGraphQL := objectiveMappingGHAPIGraphQL + oldGetArray := objectiveMappingGHAPIGetArray + t.Cleanup(func() { + objectiveMappingGHAPIGraphQL = oldGraphQL + objectiveMappingGHAPIGetArray = oldGetArray + }) + + objectiveMappingGHAPIGraphQL = func(query string, repo string) (map[string]any, error) { + return map[string]any{ + "data": map[string]any{ + "repository": map[string]any{ + "pullRequest": map[string]any{ + "id": "PR_kwDOAAABCD4", + "closingIssuesReferences": map[string]any{ + "nodes": []any{ + map[string]any{ + "id": "I_kwDOAAABCQ4", + "url": "https://github.com/owner/repo/issues/1234", + "labels": map[string]any{"nodes": []any{ + map[string]any{"name": "agentic-campaign"}, + }}, + }, + map[string]any{ + "id": "I_kwDOAAABCR4", + "url": "https://github.com/owner/repo/issues/1235", + "labels": map[string]any{"nodes": []any{ + map[string]any{"name": "security"}, + }}, + }, + }, + }, + }, + }, + }, + }, nil + } + objectiveMappingGHAPIGetArray = func(endpoint string, repo string) ([]map[string]any, error) { + return []map[string]any{{"name": "automation"}}, nil + } + + report := OutcomeReport{Type: "create_pull_request", ObjectURL: "https://github.com/owner/repo/pull/77", ObjectNumber: 77} + mapping := &github.ObjectiveMapping{ + LabelToValue: map[string]int{"agentic-campaign": 90, "security": 85, "automation": 70}, + MultiLabelLogic: "max", + } + + enrichOutcomeWithObjectiveValue(&report, "owner/repo", mapping) + + assert.Equal(t, "ambiguous", report.AttributionStatus) + assert.Equal(t, "closing_issue", report.AttributionSource) + assert.Empty(t, report.TracedRootURL) + assert.Zero(t, report.ObjectiveValue) + assert.Empty(t, report.ObjectiveLabels) } func TestNormalizeOutcomeEvaluationTargetExistsOnly(t *testing.T) { diff --git a/pkg/intent/resolver.go b/pkg/intent/resolver.go new file mode 100644 index 00000000000..28c934de236 --- /dev/null +++ b/pkg/intent/resolver.go @@ -0,0 +1,155 @@ +package intent + +type AttributionStatus string + +const ( + AttributionMapped AttributionStatus = "mapped" + AttributionUnmapped AttributionStatus = "unmapped" + AttributionUnlinked AttributionStatus = "unlinked" + AttributionAmbiguous AttributionStatus = "ambiguous" + AttributionSuggested AttributionStatus = "suggested" +) + +type AttributionSource string + +const ( + SourceExplicitMetadata AttributionSource = "explicit_metadata" + SourceClosingIssue AttributionSource = "closing_issue" + SourceParentIssue AttributionSource = "parent_issue" + SourceReferencedIssue AttributionSource = "referenced_issue" + SourceProject AttributionSource = "project" + SourceMilestone AttributionSource = "milestone" + SourceIssueLabels AttributionSource = "issue_labels" + SourceArtifactLabels AttributionSource = "artifact_labels" + SourceSuggestion AttributionSource = "suggestion" + SourceNone AttributionSource = "none" +) + +type IntentRecord struct { + Status AttributionStatus `json:"status"` + Source AttributionSource `json:"source"` + + RootNodeID string `json:"root_node_id,omitempty"` + RootType string `json:"root_type,omitempty"` + RootURL string `json:"root_url,omitempty"` + + Labels []string `json:"labels,omitempty"` + + Rule string `json:"rule,omitempty"` + ResolverVersion string `json:"resolver_version,omitempty"` +} + +type RootReference struct { + NodeID string + Type string + URL string + Labels []string +} + +type PullRequestData struct { + NodeID string + URL string + Labels []string + ExplicitIntent *IntentRecord + ClosingIssues []RootReference +} + +type Resolver struct { + ResolverVersion string + MatchLabels func(labels []string) []string +} + +func (r Resolver) ResolvePullRequest(pr PullRequestData) IntentRecord { + if pr.ExplicitIntent != nil { + intent := *pr.ExplicitIntent + if intent.ResolverVersion == "" { + intent.ResolverVersion = r.ResolverVersion + } + return intent + } + + switch len(pr.ClosingIssues) { + case 1: + return r.fromRoot(pr.ClosingIssues[0], SourceClosingIssue, "single_closing_issue") + case 0: + if len(pr.Labels) > 0 { + return r.fromLabels(pr.NodeID, pr.URL, pr.Labels, SourceArtifactLabels, "pull_request_label_fallback") + } + return r.unlinked("no_supported_intent_source") + default: + return r.ambiguous(SourceClosingIssue, "multiple_closing_issues") + } +} + +func (r Resolver) ResolveIssue(nodeID, url string, labels []string) IntentRecord { + if len(labels) == 0 { + return r.unlinked("no_supported_intent_source") + } + return r.fromLabels(nodeID, url, labels, SourceIssueLabels, "issue_label_fallback") +} + +func (r Resolver) fromRoot(root RootReference, source AttributionSource, rule string) IntentRecord { + return IntentRecord{ + Status: r.statusForLabels(root.Labels), + Source: source, + RootNodeID: root.NodeID, + RootType: root.Type, + RootURL: root.URL, + Labels: cloneStrings(root.Labels), + Rule: rule, + ResolverVersion: r.ResolverVersion, + } +} + +func (r Resolver) fromLabels(nodeID, url string, labels []string, source AttributionSource, rule string) IntentRecord { + return IntentRecord{ + Status: r.statusForLabels(labels), + Source: source, + RootNodeID: nodeID, + RootType: "artifact", + RootURL: url, + Labels: cloneStrings(labels), + Rule: rule, + ResolverVersion: r.ResolverVersion, + } +} + +func (r Resolver) unlinked(rule string) IntentRecord { + return IntentRecord{ + Status: AttributionUnlinked, + Source: SourceNone, + Rule: rule, + ResolverVersion: r.ResolverVersion, + } +} + +func (r Resolver) ambiguous(source AttributionSource, rule string) IntentRecord { + return IntentRecord{ + Status: AttributionAmbiguous, + Source: source, + Rule: rule, + ResolverVersion: r.ResolverVersion, + } +} + +func (r Resolver) statusForLabels(labels []string) AttributionStatus { + if len(labels) == 0 { + return AttributionUnlinked + } + if r.MatchLabels == nil { + return AttributionUnmapped + } + if len(r.MatchLabels(labels)) > 0 { + return AttributionMapped + } + return AttributionUnmapped +} + +func cloneStrings(values []string) []string { + if len(values) == 0 { + return nil + } + cloned := make([]string, len(values)) + copy(cloned, values) + return cloned +} diff --git a/pkg/intent/resolver_test.go b/pkg/intent/resolver_test.go new file mode 100644 index 00000000000..660e2e99143 --- /dev/null +++ b/pkg/intent/resolver_test.go @@ -0,0 +1,118 @@ +package intent + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResolverResolvePullRequestSingleClosingIssueMapped(t *testing.T) { + resolver := Resolver{ + ResolverVersion: "test-v1", + MatchLabels: func(labels []string) []string { + if len(labels) == 0 { + return nil + } + return []string{"security"} + }, + } + + intent := resolver.ResolvePullRequest(PullRequestData{ + NodeID: "PR_kwDOAAABCD4", + URL: "https://github.com/owner/repo/pull/77", + ClosingIssues: []RootReference{{ + NodeID: "I_kwDOAAABCQ4", + Type: "issue", + URL: "https://github.com/owner/repo/issues/1234", + Labels: []string{"security", "critical"}, + }}, + }) + + assert.Equal(t, AttributionMapped, intent.Status) + assert.Equal(t, SourceClosingIssue, intent.Source) + assert.Equal(t, "I_kwDOAAABCQ4", intent.RootNodeID) + assert.Equal(t, "issue", intent.RootType) + assert.Equal(t, "https://github.com/owner/repo/issues/1234", intent.RootURL) + assert.Equal(t, []string{"security", "critical"}, intent.Labels) + assert.Equal(t, "single_closing_issue", intent.Rule) + assert.Equal(t, "test-v1", intent.ResolverVersion) +} + +func TestResolverResolvePullRequestSingleClosingIssueUnmapped(t *testing.T) { + resolver := Resolver{ + MatchLabels: func(labels []string) []string { + return nil + }, + } + + intent := resolver.ResolvePullRequest(PullRequestData{ + ClosingIssues: []RootReference{{ + Type: "issue", + URL: "https://github.com/owner/repo/issues/1234", + Labels: []string{"triage"}, + }}, + }) + + assert.Equal(t, AttributionUnmapped, intent.Status) + assert.Equal(t, SourceClosingIssue, intent.Source) + assert.Equal(t, "single_closing_issue", intent.Rule) +} + +func TestResolverResolvePullRequestArtifactFallbackMapped(t *testing.T) { + resolver := Resolver{ + MatchLabels: func(labels []string) []string { + return []string{"automation"} + }, + } + + intent := resolver.ResolvePullRequest(PullRequestData{ + NodeID: "PR_kwDOAAABCD4", + URL: "https://github.com/owner/repo/pull/77", + Labels: []string{"automation"}, + }) + + assert.Equal(t, AttributionMapped, intent.Status) + assert.Equal(t, SourceArtifactLabels, intent.Source) + assert.Equal(t, "pull_request_label_fallback", intent.Rule) + assert.Equal(t, "artifact", intent.RootType) + assert.Equal(t, "https://github.com/owner/repo/pull/77", intent.RootURL) +} + +func TestResolverResolvePullRequestNoSourcesUnlinked(t *testing.T) { + resolver := Resolver{} + + intent := resolver.ResolvePullRequest(PullRequestData{}) + + assert.Equal(t, AttributionUnlinked, intent.Status) + assert.Equal(t, SourceNone, intent.Source) + assert.Equal(t, "no_supported_intent_source", intent.Rule) +} + +func TestResolverResolvePullRequestMultipleClosingIssuesAmbiguous(t *testing.T) { + resolver := Resolver{} + + intent := resolver.ResolvePullRequest(PullRequestData{ + ClosingIssues: []RootReference{{URL: "https://github.com/owner/repo/issues/1"}, {URL: "https://github.com/owner/repo/issues/2"}}, + }) + + assert.Equal(t, AttributionAmbiguous, intent.Status) + assert.Equal(t, SourceClosingIssue, intent.Source) + assert.Equal(t, "multiple_closing_issues", intent.Rule) + assert.Empty(t, intent.RootURL) +} + +func TestResolverResolveIssueMapped(t *testing.T) { + resolver := Resolver{ + MatchLabels: func(labels []string) []string { + return []string{"documentation"} + }, + } + + intent := resolver.ResolveIssue("I_kwDOAAABCQ4", "https://github.com/owner/repo/issues/42", []string{"documentation"}) + + assert.Equal(t, AttributionMapped, intent.Status) + assert.Equal(t, SourceIssueLabels, intent.Source) + assert.Equal(t, "issue_label_fallback", intent.Rule) + assert.Equal(t, "artifact", intent.RootType) + assert.Equal(t, []string{"documentation"}, intent.Labels) +} diff --git a/pkg/workflow/action_resolver.go b/pkg/workflow/action_resolver.go index 34df2779e61..cf132cc2a18 100644 --- a/pkg/workflow/action_resolver.go +++ b/pkg/workflow/action_resolver.go @@ -166,15 +166,15 @@ func ResolveGhAwRef(ctx context.Context, ref string) (string, error) { apiPath := fmt.Sprintf("/repos/github/gh-aw/commits/%s", ref) callCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() -cmd := ExecGHContext(callCtx, "api", apiPath, "--jq", ".sha") -output, err := cmd.CombinedOutput() -if err != nil { - msg := strings.TrimSpace(string(output)) - if msg != "" { - return "", fmt.Errorf("failed to resolve gh-aw ref %q to SHA: %s: %w", ref, msg, err) + cmd := ExecGHContext(callCtx, "api", apiPath, "--jq", ".sha") + output, err := cmd.CombinedOutput() + if err != nil { + msg := strings.TrimSpace(string(output)) + if msg != "" { + return "", fmt.Errorf("failed to resolve gh-aw ref %q to SHA: %s: %w", ref, msg, err) + } + return "", fmt.Errorf("failed to resolve gh-aw ref %q to SHA: %w", ref, err) } - return "", fmt.Errorf("failed to resolve gh-aw ref %q to SHA: %w", ref, err) -} sha := strings.TrimSpace(string(output)) if !gitutil.IsValidFullSHA(sha) { return "", fmt.Errorf("unexpected response resolving gh-aw ref %q: got %q (expected 40-char hex SHA)", ref, sha) diff --git a/specs/intent-attribution-agent-governance.md b/specs/intent-attribution-agent-governance.md new file mode 100644 index 00000000000..6a2a596598a --- /dev/null +++ b/specs/intent-attribution-agent-governance.md @@ -0,0 +1,1218 @@ +--- + +title: Intent Attribution & Agent Governance Specification +version: 2.0.0 +status: Partially Implemented +date: 2026-06-09 +last_updated: 2026-06-12 +replaces: objective-mapping-portfolio-reporting.md +-------------------------------------------------- + +# Intent Attribution & Agent Governance Specification + +## Summary + +This specification defines a deterministic intent layer for agentic GitHub workflows. + +The system connects GitHub work to structured context such as: + +* priority +* domain +* initiative +* risk +* root issue + +That context can be used for two purposes: + +1. **Attribution and reporting** — explain what work an artifact supported and how reliably that relationship is known +2. **Workflow governance** — determine what an agent may do, which checks are required, and whether human approval is necessary + +The central principle is: + +> **Intent determines authority. Execution produces evidence.** + +The system does not claim that GitHub labels or merged pull requests prove business impact, ROI, or realized customer value. + +## Current implementation + +The existing implementation provides the initial attribution and reporting foundation: + +1. A shared GitHub utility loads `.github/objective-mapping.json` +2. Labels are mapped to numeric weights through `ObjectiveMapping` +3. CLI outcome reports include: + + * `objective_value` + * `objective_labels` + * `traced_root_url` +4. Pull request outcomes trace to closing issues before labels are evaluated +5. Direct issue labels are used as a fallback +6. Outcome summaries aggregate attempted and accepted weights +7. Per-label breakdowns aggregate accepted, rejected, and pending outcomes + +These capabilities remain supported. + +In this specification, they are treated as an early implementation of **intent attribution**, not as proof of business impact. + +## Product boundary + +The system can establish: + +* what GitHub artifact was produced +* whether the artifact was accepted, rejected, or remains pending +* which explicit GitHub relationship connected it to a root object +* which configured labels were found +* which deterministic rule was applied +* which workflow policy should govern the work +* which checks and approvals were required +* which execution evidence was recorded + +The system does not independently establish: + +* financial value +* ROI +* employee productivity +* customer value +* strategic success +* causal business impact + +Those claims require separate evidence. + +## Core model + +```text +Intent + ↓ +Attribution + ↓ +Risk classification + ↓ +Policy compilation + ↓ +Agent execution + ↓ +GitHub artifact + ↓ +Outcome evaluation + ↓ +Evidence +``` + +The model distinguishes five concepts. + +### Intent + +Why the work exists and what context applies. + +Examples: + +* critical +* security +* authentication modernization +* documentation +* production incident + +### Attribution + +How the intent was connected to the work. + +Examples: + +* explicit workflow metadata +* closing issue +* parent issue +* direct issue labels +* pull request labels + +### Policy + +What the agent is permitted and required to do. + +Examples: + +* propose only +* supervised execution +* bounded autonomous execution +* required security tests +* mandatory human approval +* auto-merge prohibited + +### Outcome + +What observable GitHub state occurred. + +Examples: + +* pull request merged +* pull request closed without merge +* issue completed +* work still pending + +### Evidence + +What proves that the required process occurred. + +Examples: + +* test results +* review approval +* policy decision +* workflow trace +* GitHub artifact state + +## Design principles + +### Deterministic authority + +Official attribution and workflow authorization must be derived from: + +* explicit GitHub metadata +* repository or organization configuration +* deterministic precedence rules + +LLMs may propose classifications or relationships, but suggestions must not affect official authorization or reporting until confirmed. + +### Unknown is not zero + +Missing attribution must not be represented as zero importance. + +```json +{ + "status": "unlinked", + "weight": null +} +``` + +A zero value means an explicit configured value of zero. + +A null value means unknown or unavailable. + +### Fail closed + +Unknown, invalid, or ambiguous intent must result in the safest applicable workflow policy. + +### Provenance is required + +Every attribution and policy decision must explain: + +* the source +* the rule +* the root object +* the configuration version +* any overrides + +### Artifacts are not objectives + +A pull request is an execution artifact. + +An issue or explicitly declared objective represents intended work. + +Multiple pull requests connected to one issue must not automatically multiply the number of completed objectives. + +## Intent configuration + +The initial implementation continues to support: + +```text +.github/objective-mapping.json +``` + +A future migration may introduce: + +```text +.github/intent-policy.json +``` + +### Compatibility configuration + +```json +{ + "label_to_value": { + "critical": 100, + "p0": 100, + "p1": 50, + "security": 40 + }, + "multi_label_logic": "max", + "priority_labels": [ + "critical", + "p0", + "p1" + ] +} +``` + +Existing numeric values are interpreted as **relative weights**, not financial value or verified impact. + +### Target configuration + +```json +{ + "version": 1, + "labels": { + "critical": { + "dimension": "priority", + "value": "critical", + "weight": 100 + }, + "p1": { + "dimension": "priority", + "value": "high", + "weight": 50 + }, + "security": { + "dimension": "domain", + "value": "security" + }, + "documentation": { + "dimension": "domain", + "value": "documentation" + }, + "high-risk": { + "dimension": "risk", + "value": "high" + }, + "auth-modernization": { + "dimension": "initiative", + "value": "auth-modernization" + } + }, + "scoring": { + "dimension": "priority", + "strategy": "max" + }, + "attribution": { + "multiple_roots": "ambiguous", + "allow_artifact_label_fallback": true + } +} +``` + +Separating dimensions prevents initiatives, priorities, domains, and risk labels from competing in one flat scoring calculation. + +Only the configured scoring dimension contributes to weight. + +## Intent record + +```go +type IntentRecord struct { + Status AttributionStatus `json:"status"` + Source AttributionSource `json:"source"` + + Objective string `json:"objective,omitempty"` + Initiative string `json:"initiative,omitempty"` + Priority string `json:"priority,omitempty"` + Domains []string `json:"domains,omitempty"` + Risk string `json:"risk,omitempty"` + + RootNodeID string `json:"root_node_id,omitempty"` + RootType string `json:"root_type,omitempty"` + RootURL string `json:"root_url,omitempty"` + + Labels []string `json:"labels,omitempty"` + Weight *int `json:"weight"` + + Rule string `json:"rule"` + ConfigHash string `json:"config_hash"` + ResolverVersion string `json:"resolver_version"` +} +``` + +## Attribution states + +```go +type AttributionStatus string + +const ( + AttributionMapped AttributionStatus = "mapped" + AttributionUnmapped AttributionStatus = "unmapped" + AttributionUnlinked AttributionStatus = "unlinked" + AttributionAmbiguous AttributionStatus = "ambiguous" + AttributionSuggested AttributionStatus = "suggested" +) +``` + +### `mapped` + +A deterministic source was found and at least one configured intent label matched. + +### `unmapped` + +A root object was found, but its labels did not match the configuration. + +### `unlinked` + +No supported root or intent source was found. + +### `ambiguous` + +Multiple candidate roots were found and no deterministic policy selected one. + +### `suggested` + +A heuristic or AI-generated relationship exists but has not been confirmed. + +Suggested attribution does not contribute to official metrics or policy decisions. + +## Attribution sources + +```go +type AttributionSource string + +const ( + SourceExplicitMetadata AttributionSource = "explicit_metadata" + SourceClosingIssue AttributionSource = "closing_issue" + SourceParentIssue AttributionSource = "parent_issue" + SourceReferencedIssue AttributionSource = "referenced_issue" + SourceProject AttributionSource = "project" + SourceMilestone AttributionSource = "milestone" + SourceIssueLabels AttributionSource = "issue_labels" + SourceArtifactLabels AttributionSource = "artifact_labels" + SourceSuggestion AttributionSource = "suggestion" + SourceNone AttributionSource = "none" +) +``` + +## Deterministic resolution + +Resolution order: + +```text +1. Explicit workflow intent +2. Single closing issue +3. Parent or sub-issue relationship +4. Explicit referenced issue +5. Project or campaign context +6. Milestone +7. Direct artifact labels +8. Suggested attribution +9. Unlinked +``` + +Initial implementation: + +```go +func (r *Resolver) Resolve(pr PullRequestData) IntentRecord { + if pr.ExplicitIntent != nil { + return r.fromExplicitIntent(pr.ExplicitIntent) + } + + switch len(pr.ClosingIssues) { + case 1: + return r.fromRoot( + pr.ClosingIssues[0], + SourceClosingIssue, + "single_closing_issue", + ) + + case 0: + if len(pr.Labels) > 0 { + return r.fromLabels( + pr.NodeID, + pr.URL, + pr.Labels, + SourceArtifactLabels, + "pull_request_label_fallback", + ) + } + + return r.unlinked("no_supported_intent_source") + + default: + return r.ambiguous( + SourceClosingIssue, + "multiple_closing_issues", + ) + } +} +``` + +The resolver must not silently select the first of multiple closing issues. + +## Multiple-root policy + +Default: + +```text +0 candidates → continue resolution +1 candidate → use candidate +2+ candidates → ambiguous +``` + +Future supported policies may include: + +* explicit primary root +* highest-priority root +* all roots +* fractional attribution + +The active policy must be recorded in decision provenance. + +## Risk classification + +Risk should be explicit where possible. + +When risk is absent, deterministic rules may derive it. + +Example: + +```text +security + critical → high +production → high +infrastructure → medium +dependency update → medium +documentation → low +unknown → unknown +``` + +```go +func ResolveRisk(intent IntentRecord) string { + if intent.Risk != "" { + return intent.Risk + } + + if contains(intent.Domains, "security") && + intent.Priority == "critical" { + return "high" + } + + if contains(intent.Domains, "production") { + return "high" + } + + if contains(intent.Domains, "infrastructure") { + return "medium" + } + + if contains(intent.Domains, "documentation") { + return "low" + } + + return "unknown" +} +``` + +## Execution policy + +```go +type ExecutionPolicy struct { + Autonomy string `json:"autonomy"` + + AllowedTools []string `json:"allowed_tools"` + DeniedTools []string `json:"denied_tools"` + + WriteScope string `json:"write_scope"` + + RequiredChecks []string `json:"required_checks"` + + HumanApprovalRequired bool `json:"human_approval_required"` + AutoMergeAllowed bool `json:"auto_merge_allowed"` + + MaxAttempts int `json:"max_attempts"` + + RuleIDs []string `json:"rule_ids"` +} +``` + +Supported initial autonomy levels: + +### `propose_only` + +The agent may inspect the repository and propose a plan or patch. + +The agent may not modify the repository. + +### `supervised` + +The agent may create changes on a feature branch and open a pull request. + +Human approval is required before merge. + +### `bounded` + +The agent may complete the workflow within explicitly configured limits. + +Auto-merge may be permitted after required checks pass. + +## Policy precedence + +```text +organization constraints +> repository constraints +> intent-specific rules +> workflow defaults +> agent request +``` + +A lower-precedence rule may not weaken a higher-precedence constraint. + +Example: + +```json +{ + "rules": [ + { + "id": "security-critical", + "when": { + "domain": "security", + "priority": "critical" + }, + "set": { + "autonomy": "supervised", + "write_scope": "feature_branch", + "required_checks": [ + "unit-tests", + "security-tests", + "dependency-review" + ], + "human_approval_required": true, + "auto_merge_allowed": false, + "max_attempts": 2 + } + }, + { + "id": "documentation-low-risk", + "when": { + "domain": "documentation", + "risk": "low" + }, + "set": { + "autonomy": "bounded", + "write_scope": "feature_branch", + "required_checks": [ + "documentation-build" + ], + "human_approval_required": false, + "auto_merge_allowed": true, + "max_attempts": 3 + } + }, + { + "id": "unknown-default", + "when": { + "risk": "unknown" + }, + "set": { + "autonomy": "propose_only", + "write_scope": "none", + "human_approval_required": true, + "auto_merge_allowed": false, + "max_attempts": 1 + } + } + ] +} +``` + +## Safe default + +```go +func safestDefaultPolicy() ExecutionPolicy { + return ExecutionPolicy{ + Autonomy: "propose_only", + WriteScope: "none", + HumanApprovalRequired: true, + AutoMergeAllowed: false, + MaxAttempts: 1, + } +} +``` + +Unknown or ambiguous intent must not grant elevated authority. + +## Policy compilation + +```go +type PolicyCompiler struct { + Rules []PolicyRule +} + +func (c *PolicyCompiler) Compile( + intent IntentRecord, + repository RepositoryContext, +) ExecutionPolicy { + policy := safestDefaultPolicy() + + for _, rule := range c.Rules { + if rule.Matches(intent, repository) { + policy = mergePolicy(policy, rule.Set) + policy.RuleIDs = append( + policy.RuleIDs, + rule.ID, + ) + } + } + + return policy +} +``` + +Policy merging must preserve stricter higher-precedence constraints. + +## Decision provenance + +```go +type PolicyDecision struct { + Intent IntentRecord `json:"intent"` + Policy ExecutionPolicy `json:"policy"` + + AppliedRules []AppliedRule `json:"applied_rules"` + Overrides []PolicyOverride `json:"overrides"` + + ConfigHash string `json:"config_hash"` + CompilerVersion string `json:"compiler_version"` +} +``` + +Example: + +```json +{ + "policy": { + "autonomy": "supervised", + "human_approval_required": true, + "auto_merge_allowed": false + }, + "applied_rules": [ + { + "id": "security-critical", + "reason": "domain=security and priority=critical" + } + ], + "overrides": [ + { + "field": "auto_merge_allowed", + "requested": true, + "effective": false, + "reason": "organization security policy" + } + ] +} +``` + +## Enforcement + +The orchestrator must enforce the compiled policy at runtime. + +Policy must not exist only in an agent prompt. + +```go +func (o *Orchestrator) Execute( + ctx context.Context, + request WorkflowRequest, +) error { + intent := o.intentResolver.Resolve(request.WorkItem) + + intent.Risk = ResolveRisk(intent) + + policy := o.policyCompiler.Compile( + intent, + request.Repository, + ) + + if err := o.authorizer.Validate( + request, + policy, + ); err != nil { + return err + } + + runtime := NewRestrictedRuntime(policy) + + return runtime.Run(ctx, request.Workflow) +} +``` + +Individual tool calls must be authorized: + +```go +func (a *Authorizer) AuthorizeTool( + policy ExecutionPolicy, + tool string, +) error { + if slices.Contains(policy.DeniedTools, tool) { + return ErrToolDenied + } + + if !slices.Contains(policy.AllowedTools, tool) { + return ErrToolNotAllowed + } + + return nil +} +``` + +The agent must not be able to modify or expand its own policy. + +## Outcome evaluation + +Initial observable rules: + +```text +merged pull request → accepted +closed unmerged pull request → rejected +open pull request → pending + +completed issue → accepted +closed as not planned → rejected +open issue → pending +``` + +```go +type OutcomeRecord struct { + ArtifactURL string `json:"artifact_url"` + Status string `json:"status"` + + Intent IntentRecord `json:"intent"` + Policy ExecutionPolicy `json:"policy"` + + EvaluatedAt time.Time `json:"evaluated_at"` +} +``` + +An accepted artifact is evidence of accepted execution. + +It does not independently prove realized business impact. + +## Evidence record + +```go +type EvidenceRecord struct { + WorkflowRunID string `json:"workflow_run_id"` + ArtifactURL string `json:"artifact_url"` + + RequiredChecks []string `json:"required_checks"` + PassedChecks []string `json:"passed_checks"` + FailedChecks []string `json:"failed_checks"` + + HumanApprovalRequired bool `json:"human_approval_required"` + HumanApprovalReceived bool `json:"human_approval_received"` + + Outcome string `json:"outcome"` + + TraceID string `json:"trace_id,omitempty"` +} +``` + +## Attribution reporting + +The existing weighted reporting remains useful when interpreted correctly. + +### Attribution coverage + +```text +mapped outcomes / all evaluated outcomes +``` + +### Acceptance rate + +```text +accepted outcomes / attempted outcomes +``` + +### Weighted acceptance rate + +```text +accepted mapped weight / attempted mapped weight +``` + +Weighted acceptance measures delivery performance across configured relative weights. + +It is not ROI, planned-value completion, or verified business impact. + +Every weighted result must be shown alongside attribution coverage. + +```text +Weighted acceptance: 78% +Attribution coverage: 42% +``` + +## Unique root reporting + +Strategic reporting must deduplicate root work items. + +```text +Five merged pull requests +connected to one issue += +one attributed root +``` + +Root completion must come from the root object's state or explicit completion evidence. + +A merged pull request alone must not automatically mark the full root objective complete. + +## OpenTelemetry + +OpenTelemetry is the execution-observability layer. + +It is not the authoritative intent store. + +One trace should represent one workflow execution: + +```text +agentic.workflow.run +├── intent.resolve +├── risk.resolve +├── policy.compile +├── authorization.validate +├── agent.execute +├── github.artifact.create +├── checks.evaluate +├── approval.evaluate +└── outcome.evaluate +``` + +Recommended span attributes: + +```text +github.intent.status +github.intent.source +github.intent.priority +github.intent.risk +github.intent.domain + +agent.policy.autonomy +agent.policy.write_scope +agent.policy.human_approval_required +agent.policy.auto_merge_allowed + +github.artifact.type +github.artifact.outcome +``` + +High-cardinality identifiers belong on spans or persisted records, not metric dimensions. + +Examples: + +* pull request URL +* issue URL +* node ID +* trace ID +* workflow run ID + +## Metrics + +Initial operational metrics: + +```text +agent.workflow.runs +agent.workflow.denied +agent.workflow.duration + +github.intent.resolutions +github.intent.attribution.coverage + +agent.policy.decisions +agent.policy.overrides + +github.artifacts.created +github.artifacts.accepted +github.artifacts.rejected +``` + +Useful low-cardinality dimensions: + +```text +intent.status +intent.source +priority +risk +domain +autonomy +outcome +``` + +## CLI + +### Explain policy before execution + +```bash +gh aw policy explain \ + --repo acme/platform \ + --issue 123 +``` + +Example: + +```text +Intent + Priority: critical + Domain: security + Risk: high + Source: issue labels + +Execution policy + Autonomy: supervised + Write scope: feature branch + Human approval: required + Auto-merge: prohibited + Maximum attempts: 2 + +Required checks + unit-tests + security-tests + dependency-review + +Applied rules + security-critical + organization-security-baseline +``` + +### Report outcomes + +```bash +gh aw outcomes report \ + --repo acme/platform +``` + +Example: + +```text +Outcomes + Total: 40 + Accepted: 28 + Rejected: 7 + Pending: 5 + +Intent attribution + Mapped: 17 + Unmapped: 6 + Unlinked: 14 + Ambiguous: 3 + Coverage: 42.5% + +Weighted delivery + Attempted weight: 1150 + Accepted weight: 900 + Weighted acceptance: 78.3% + +Unique attributed roots: 12 +``` + +## Implementation phases + +### Phase 1: current foundation + +Already implemented or partially implemented: + +1. Load label-to-weight mapping +2. Compute weights from labels +3. Trace pull requests to closing issues +4. Record root URL +5. Enrich outcome reports +6. Aggregate accepted and attempted weights +7. Produce per-label breakdowns + +### Phase 2: honest attribution model + +Implement: + +1. Rename value semantics to relative weight +2. Add attribution states +3. Add attribution source +4. Make unknown weight nullable +5. Record root node ID +6. Mark multiple roots ambiguous +7. Add attribution coverage +8. Rename objective efficiency to weighted acceptance rate +9. Deduplicate root work items +10. Separate priority, domain, initiative, and risk dimensions + +### Phase 3: prove attribution value + +Before intent affects authority, the system must show that attribution is useful for analysis. + +Validate: + +1. Attribution coverage is high enough to be decision-relevant +2. Mapped categories reveal non-trivial work patterns +3. Unique-root reporting is more informative than raw artifact counts +4. Weighted acceptance is always shown alongside coverage +5. Manual samples show that mapped results are directionally correct + +Deliver: + +1. Coverage reporting by state: mapped, unmapped, unlinked, ambiguous +2. Unique-root reporting +3. Weighted acceptance over mapped items only +4. Representative manual-review samples for correctness checking + +If this phase does not show clear analytical value, intent remains a reporting feature and does not drive policy. + +### Phase 4: prove attribution trustworthiness + +Before intent affects authority, the system must show that attribution is trustworthy enough for control. + +Validate: + +1. Identical GitHub state and configuration produce identical attribution +2. Ambiguous and unlinked cases fail closed +3. Source precedence is understandable and auditable +4. Fallback paths do not silently distort authority decisions +5. Manual validation shows high precision for cases that would change authority + +Deliver: + +1. Attribution provenance for every official decision +2. Determinism tests +3. Ambiguity and fallback reporting +4. Source-quality analysis by attribution source + +If this phase does not show sufficient trustworthiness, intent remains analytics only. + +### Phase 5: minimal intent-aware governance + +Implement: + +1. Safe default for ambiguous and unlinked intent +2. Minimal policy distinctions with clear operational value +3. A narrow policy explanation surface such as `gh aw policy explain` +4. Explicit fail-closed behavior when attribution is missing or disputed + +Suggested initial trial: + +1. Ambiguous or unlinked intent becomes `propose_only` +2. Explicitly high-risk or security-like intent becomes `supervised` +3. Low-risk documentation work may become `bounded` + +This phase should remain intentionally small. It is a controlled trial, not a full policy framework. + +### Phase 6: broader governance and execution evidence + +Implement: + +1. Risk resolution beyond simple deterministic categories +2. General policy compilation +3. Tool authorization +4. Write-scope enforcement +5. Required checks +6. Human approval requirement +7. Auto-merge restrictions +8. Decision provenance +9. OpenTelemetry workflow traces +10. Policy-decision spans +11. Authorization events +12. Evidence records +13. Low-cardinality operational metrics +14. Asynchronous trace links for later GitHub outcomes + +### Phase 7: broader intent relationships + +Potential extensions: + +1. Parent and sub-issue resolution +2. Projects and milestones +3. Cross-repository initiatives +4. Organization-level policies +5. Suggested attribution requiring confirmation +6. External production or customer evidence + +## Testing + +### Attribution tests + +* One mapped closing issue +* One unmapped closing issue +* No closing issue +* Pull request label fallback +* Multiple closing issues +* Null weight for unknown attribution +* Case-insensitive label normalization +* Root deduplication + +### Attribution value tests + +* Coverage is reported alongside weighted acceptance +* Unique-root counts differ from raw artifact counts when many artifacts map to one root +* Mapped-only weighted reporting excludes unlinked and ambiguous items +* Representative samples can be produced for manual correctness review + +### Attribution trust tests + +* Multiple closing issues fail closed as ambiguous +* Artifact-label fallback is reported as fallback provenance +* Identical input state produces identical attribution output +* Missing or ambiguous attribution does not grant elevated authority + +### Policy tests + +* Critical security work becomes supervised +* Low-risk documentation work becomes bounded +* Unknown risk becomes propose-only +* Organization policy overrides repository policy +* Required approval disables auto-merge +* Less restrictive rules cannot weaken stronger constraints + +### Enforcement tests + +* Denied tools cannot execute +* Write scope cannot be expanded +* Agent cannot modify its own policy +* Failed required checks prevent completion +* Missing approval prevents merge when required + +### Determinism test + +Given identical: + +* GitHub state +* configuration +* resolver version +* compiler version + +the normalized intent and policy outputs must be identical. + +## Release gates + +### Gate 1: attribution value proven + +Proceed beyond attribution-only reporting only when: + +1. Coverage is measured and visible beside weighted reporting +2. Root deduplication produces materially different and more honest reporting than artifact counts alone +3. Manual review shows that mapped results are directionally useful +4. The mapped categories reveal meaningful work patterns rather than label noise + +### Gate 2: attribution trustworthy enough for control + +Proceed to governance only when: + +1. Deterministic resolution is demonstrated +2. Ambiguous and unlinked cases fail closed +3. Attribution provenance is available for official decisions +4. Manual validation shows sufficient precision for authority-changing cases +5. Fallback logic is auditable and not silently permissive + +## Definition of done + +### Attribution release done + +The attribution release is complete when: + +1. A GitHub issue or pull request resolves into a normalized intent record +2. Missing and ambiguous intent are represented explicitly +3. Coverage, ambiguity, and unique-root reporting are available +4. Weighted acceptance is reported only with attribution coverage beside it +5. Manual sampling can be used to assess mapping quality + +### Initial governance release done + +The initial governance release is complete when: + +1. The attribution release is already complete +2. Intent deterministically compiles into at least one minimal execution-policy distinction +3. Ambiguous and unlinked intent receive the safest available policy +4. Runtime behavior is restricted by policy for the initial governed cases +5. Human approval and check requirements are enforced for the initial governed cases +6. Every policy decision records enough provenance to audit why authority was granted or denied +7. Every governed run emits execution telemetry +8. Every resulting artifact receives an outcome and evidence record +9. No LLM decision is required for official authorization + +## Product position + +This system is not a business-impact calculator. + +It is a deterministic control layer for agentic GitHub work. + +> **Intent determines authority. Execution produces evidence.** diff --git a/specs/objective-mapping-portfolio-reporting.md b/specs/objective-mapping-portfolio-reporting.md deleted file mode 100644 index 4552be59c76..00000000000 --- a/specs/objective-mapping-portfolio-reporting.md +++ /dev/null @@ -1,571 +0,0 @@ - ---- -title: Objective Mapping & Portfolio Reporting Specification -version: 1.1.0 -status: Partially Implemented -date: 2026-06-09 -last_updated: 2026-06-10 ---- - -# Objective Mapping & Portfolio Reporting Specification - -This specification defines a reusable label-to-objective-value mapping layer for GitHub work. It also outlines later phases where that mapping can be applied to safe output outcomes, root issue tracing, and portfolio-level impact reporting. - -## Implementation Scope - -### Phase 1: Implemented Now - -The current implementation is no longer just the bare mapping layer: - -1. A shared GitHub utility loads `.github/objective-mapping.json` -2. Labels are mapped to numeric objective values through `ObjectiveMapping` -3. CLI outcome reporting enriches outcomes with `objective_value`, `objective_labels`, and `traced_root_url` -4. Pull request outcomes trace to linked closing issues before objective values are computed -5. Outcome summaries and per-objective breakdowns aggregate attempted and accepted objective value - -This phase gives GitHub work a single configurable impact vocabulary and already supports basic root-aware outcome measurement. - -### Phase 2+: Later Extensions - -The rest of this document describes natural extensions that may be added later: - -1. Root tracing beyond the current PR-to-closing-issue path, including epic resolution -2. Campaign-level aggregation and filtering in dedicated reports -3. Portfolio reporting workflows that consume the existing objective-enriched outcome data -4. Cost-aware efficiency metrics using real AI Credits data -5. Strategic analysis over delivered impact - -Those extensions are design targets, not required complexity for trying the mapping itself. - -## Overview: Impact Measurement Through Root Cause Tracing - -Longer term, objective mapping answers: **What impact did we create?** By connecting work back to the root problems it solves. - -For the MVP, the answer is simpler: **what value do these labels represent?** - -For the extended model, that grows into: - -1. **Root Problems** — Issues and epics represent actual business objectives (with PM-assigned impact values) -2. **Tracing** — Safe outputs (PRs, comments) trace backward to root issues/epics -3. **Impact Scoring** — Objectives are assigned to root problems, not intermediate artifacts -4. **Portfolio Reporting** — Aggregates impact by objective to show which business goals are being achieved - -This enables questions like: -- **What high-priority problems did we solve?** (Trace accepted PRs back to root issues, check labels) -- **Which initiatives made the most progress?** (Aggregate impact by epic) -- **What value did we create per objective?** (Sum impact values for accepted outcomes) -- **What's our ROI by problem domain?** (Efficiency = accepted value / attempted value) - -## Extended Architecture: Trace → Root → Map → Aggregate - -This architecture describes the fuller impact model beyond the current MVP mapping layer. - -### Components - -1. **Root Tracing** — Traces safe outputs (PRs, issues) back to root issue or epic -2. **ObjectiveMapping** — Maps root issue/epic labels to numeric impact values -3. **Configuration File** — `.github/objective-mapping.json` with objective values -4. **Outcome Enrichment** — GitHub API queries to fetch root objects and their labels -5. **Portfolio Report** — Aggregates impact by objective, showing what value was created - -### Design Principles - -1. **Root Source of Truth** — Objectives are assigned to root issues/epics, not PRs or comments -2. **Traceability** — All work must trace back through GitHub's native linking (PR → issue) -3. **Centralized Configuration** — Single source of truth at `.github/objective-mapping.json` -4. **PM-Assigned Impact** — Labels on root objects represent business priorities -5. **Portfolio Visibility** — Aggregates show what problems were solved, what impact created - -## Campaigns & Objective Alignment - -### How Campaigns Work With Objectives - -A **campaign** is a bounded initiative organized around specific business objectives. Examples: - -- **"Q2 Performance Month"** — Campaign to improve latency (objective label: `initiative-performance`) -- **"Auth System Redesign"** — Major initiative (objective label: `epic-auth`) -- **"Critical Bug Fixes"** — Campaign to resolve urgent issues (objective label: `critical`) -- **"Testing Infrastructure"** — Initiative to improve test coverage (objective label: `testing`) - -### Campaign → Objectives → Root Issues → Impact Measurement - -``` -Campaign: "Q2 Performance Month" - ↓ -Assigned Objectives: initiative-performance (300 points) - ↓ -Root Issues Created: #1234, #5678, #9012 -(all labeled with "initiative-performance") - ↓ -Agent Creates PRs & Reviews (safe outputs) - ↓ -Safe Outputs Accepted/Rejected - ↓ -[Root Tracing] Trace PRs back to root issues - ↓ -[Objective Mapping] Fetch labels from root issues (initiative-performance) - ↓ -[Portfolio Report] Aggregate by campaign objectives: - Total attempted: 1500 points (5 PRs × 300 points each) - Delivered: 1200 points (4 accepted × 300 points) - Efficiency: 80% → Campaign on track, good progress -``` - -### Campaign Reporting - -Portfolio reports can be filtered by campaign to answer: - -| Question | Answer | Example | -|----------|--------|---------| -| **How is this campaign doing?** | Efficiency metric | "Performance Month: 75% delivered (1500/2000 points)" | -| **Which campaigns succeeded?** | High efficiency campaigns | "Auth redesign: 90% complete, critical bugs: 85% complete" | -| **Which need intervention?** | Low efficiency campaigns | "Low-priority features: only 40% delivered, investigate blocker" | -| **What's total campaign impact?** | Sum all delivered objectives | "This quarter we delivered 12,000 points across 8 campaigns" | - -### Configuration for Campaigns - -Add campaign-level labels to `.github/objective-mapping.json`: - -```json -{ - "label_to_value": { - "epic-auth": 500, - "epic-performance": 300, - "initiative-modernize": 400, - "campaign-q2-testing": 200, - "critical": 100, - "p0": 100, - "p1": 50 - }, - "multi_label_logic": "max", - "priority_labels": ["epic-auth", "epic-performance", "initiative-modernize", "campaign-q2-testing", "critical"] -} -``` - -**Strategy:** Campaigns typically use `multi_label_logic: "max"` so that a PR addressing both a campaign objective and a critical issue gets the higher value (captures the most important aspect). - -### Connecting Campaigns to Execution - -**Setup:** -1. PM defines campaign with clear objectives (e.g., "Ship auth redesign by EOQ") -2. Assign objective label to campaign (e.g., `epic-auth` with value 500) -3. All root issues in the campaign are labeled with that objective -4. Agent runs workflow against those issues - -**Measurement:** -1. Safe outputs traced back to root issues via PR links -2. Root issues have objective label (`epic-auth`) -3. Portfolio report aggregates by campaign objective -4. Shows: "Campaign delivered 500/600 planned points (83% success)" - -**Strategic Alignment:** -- Campaigns are how business divides work into initiatives -- Objectives are the labels that mark root issues as part of that campaign -- Impact measurement answers: "Did the campaign deliver what was planned?" - -## Configuration - -### File Format - -The configuration file maps objective labels (typically on root issues/epics) to impact values: - -```json -{ - "_comment": "Impact mapping for business objectives. Labels are assigned to root issues/epics by PM/team.", - "label_to_value": { - "epic-auth": 500, - "initiative-performance": 300, - "critical": 100, - "p0": 100, - "p1": 50 - }, - "multi_label_logic": "max", - "priority_labels": ["epic-auth", "initiative-performance", "critical", "p0"] -} -``` - -### Location & Precedence - -Objectives are loaded in this order (first found wins): - -1. **Environment Variable** — `OBJECTIVE_MAPPING_JSON` (full JSON string or file path) -2. **Repository File** — `.github/objective-mapping.json` -3. **Built-in Defaults** — Fallback with standard objectives - -### Typical Objective Labels - -These are assigned by PMs/teams to root issues and epics: - -- **Epics** (e.g., `epic-auth`, `initiative-modernize`) — Major initiatives worth 300–500 impact -- **Critical** (e.g., `critical`, `p0`) — Must-fix problems worth 100 impact -- **High-priority** (e.g., `p1`) — Important work worth 50 impact -- **Domains** (e.g., `security`, `performance`) — Strategic focus areas worth 30–80 impact - -### Multi-Label Logic - -When an outcome has multiple objective labels, the system applies one of three strategies: - -| Strategy | Behavior | Use Case | Example | -|----------|----------|----------|---------| -| **max** (default) | Uses highest value | Risk-based prioritization | `[bug, p0]` → 100 | -| **sum** | Adds all values | Cumulative impact | `[performance, workflow]` → 75 | -| **first** | Uses priority order | Organizational hierarchy | `[p0, testing]` → 100 (p0 first) | - -#### Example: Multi-Label Computation - -Given labels `[bug, p0, testing]` with values `{bug: 70, p0: 100, testing: 75}`: - -``` -max: max(70, 100, 75) = 100 -sum: 70 + 100 + 75 = 245 -first: depends on priority_labels order -``` - -## Current Outcome Integration and Remaining Root-Tracing Gaps - -This section describes what is already implemented in the CLI today and what still remains future work. - -### The Problem This Solves - -When a PR is merged (safe output accepted), we need to know: **What business objective did it deliver?** - -- The PR itself may have no labels -- The PR links to one or more issues -- Those issues contain the real business labels -- We must trace PR → issue → get labels → map to impact value - -This is how GitHub always worked: root issue describes the problem, PRs are the solution. - -### Data Flow - -``` -Safe output created (e.g., "create_pull_request") - ↓ -[EvaluateOutcomes] → outcome = "accepted" (merged) or "rejected" (closed) - ↓ -[enrichOutcomeWithObjectiveValue] - 1. For PR outcomes: GitHub API trace via closing issues - 2. For direct issue outcomes, or if PR tracing fails: fetch labels from the issue itself - 3. Use labels from the traced root object, not PR labels - 4. Store traced_root_url for audit trail - ↓ -ObjectiveMapping.ComputeObjectiveValue(root_labels) - ↓ -OutcomeReport populated with: - - objective_value: int - - objective_labels: []string - - traced_root_url: string - ↓ [ComputeOutcomeSummary] -OutcomeSummary aggregates: - - total_objective_value (what we attempted) - - accepted_objective_value (what succeeded) - - objective_efficiency (success rate by value) - ↓ [ComputeDomainBreakdowns] -DomainBreakdown per objective: - - attempted: count of work toward this objective - - accepted: count successfully delivered - - total_objective_value: impact points we attempted - - accepted_objective_value: impact points we delivered - - objective_efficiency: % of value we succeeded on -``` - -Current limitation: epic resolution is still a future extension. The implemented trace path is PR → closing issue, with fallback to direct issue labels. - -### Root Resolution Algorithm - -```go -func traceOutcomeRoot(obj GitHubObject, repo string) GitHubObject { - if obj.Type == "PullRequest" { - if len(obj.ClosingIssues) > 0 { - return obj.ClosingIssues[0] - } - } - - return obj -} -``` - -Future extension: - -```go -func traceToRootIssueOrEpic(obj GitHubObject, repo string) GitHubObject { - root := traceOutcomeRoot(obj, repo) - if root.Type == "Issue" && root.EpicLink != nil { - return root.EpicLink - } - return root -} -``` - -### Why Root Tracing Matters - -**Example: PR for "fix auth bug"** - -Without tracing: -- PR has no labels → objective_value = 0 → shows no impact - -With the currently implemented tracing: -- PR links to issue #1234 (labeled `agentic-campaign`, `security`) -- Root issue labels feed the mapping → objective_value is computed from the configured label map -- Outcome summaries and objective breakdowns reflect delivered value on the root issue labels - -This is the **only way** to measure what business value was created, because PRs don't carry the semantic meaning — issues do. - -## Future Portfolio Reporting: Measuring What Value Was Created - -### The Question It Answers - -Instead of: **"How many PRs did we merge?"** (25 PRs, so what?) - -This asks: **"How much business value did we deliver?"** (We aimed for 1000 impact points on our critical objectives, delivered 750, 75% success rate) - -### Impact Metrics - -Each objective (label assigned to root issues/epics by PM) shows: - -| Metric | Meaning | Example | -|--------|---------|---------| -| **Attempted** | Work started toward this objective | 20 PRs addressing `epic-auth` | -| **Accepted** | Work successfully delivered | 15 of 20 PRs merged | -| **Total Impact** | Value we tried to deliver | 20 attempts × 100 points = 2000 | -| **Delivered Impact** | Value we actually delivered | 15 successes × 100 points = 1500 | -| **Efficiency** | Percentage of value achieved | 1500 / 2000 = 75% ✅ Good progress | - -### Objective Breakdown Metrics - -Each objective is aggregated with these metrics: - -| Field | Type | Meaning | -|-------|------|---------| -| `label` | string | Business objective (e.g., `epic-auth`, `critical`) | -| `attempted` | int | Total work started on this objective | -| `accepted` | int | Work successfully delivered | -| `rejected` | int | Work that failed or was rejected | -| `pending` | int | Work still in progress | -| `total_objective_value` | int | Impact value attempted (sum of all values) | -| `accepted_objective_value` | int | Impact value delivered (sum of accepted values) | -| `objective_efficiency` | float64 | accepted / total (percentage of planned value realized) | -| `acceptance_rate` | float64 | accepted / attempted (percentage of work that succeeded) | - -### Example: Portfolio Impact Report - -```json -{ - "total": 50, - "accepted": 35, - "objective_efficiency": 0.75, - "domain_breakdowns": [ - { - "label": "epic-auth", - "attempted": 20, - "accepted": 15, - "rejected": 4, - "pending": 1, - "total_objective_value": 10000, - "accepted_objective_value": 7500, - "objective_efficiency": 0.75, - "acceptance_rate": 0.75 - }, - { - "label": "critical", - "attempted": 15, - "accepted": 14, - "rejected": 1, - "pending": 0, - "total_objective_value": 1500, - "accepted_objective_value": 1400, - "objective_efficiency": 0.93, - "acceptance_rate": 0.93 - }, - { - "label": "p1", - "attempted": 15, - "accepted": 6, - "rejected": 8, - "pending": 1, - "total_objective_value": 750, - "accepted_objective_value": 300, - "objective_efficiency": 0.40, - "acceptance_rate": 0.40 - } - ] -} -``` - -### What This Report Says - -- **Epic-auth**: Aimed for 10,000 impact on this initiative, delivered 7,500 (75% success) → Continue but monitor -- **Critical**: Aimed for 1,500 impact, delivered 1,400 (93% success) → Excellent, keep strategy -- **P1**: Aimed for 750 impact, delivered only 300 (40% success) → Investigate issues, may need human review - -### Performance Analysis: Impact-Based Insights - -The `AnalyzeDomainPerformance()` function interprets efficiency to answer: **How well are we delivering on this objective?** - -| Efficiency | Status | Meaning | -|-----------|--------|---------| -| ≥ 90% | excellent | Delivering nearly all planned value → Keep strategy, scale if possible | -| ≥ 75% | good | Strong progress on objective → Monitor for regressions, maintain discipline | -| ≥ 50% | fair | Moderate success, room to improve → Review process, may need human guidance | -| < 50% | poor | Failing to deliver value → Investigate root cause, pause or redesign automation | - -**Example Interpretations:** - -- **epic-auth at 75%**: Started with 10,000 impact points planned, delivering 7,500. We're solving most auth problems successfully, but some are slipping. Review what's failing. -- **critical at 93%**: Nearly perfect on critical issues. Strategy is working. Could increase volume. -- **p1 at 40%**: Only delivering 40% of planned p1 work. Major problems here — investigate before continuing. - -## Business Impact Model - -### Key Insight: Root Tracing is Non-Negotiable - -This system only works if we trace back to root issues/epics. Here's why: - -1. **Root issues carry business semantics** — They're labeled by PMs with strategic intent -2. **PRs are tactical** — They're solutions, not problems; they shouldn't carry business labels -3. **GitHub's native model** — Issues represent work-to-do, PRs represent work-done -4. **Audit trail** — We can show exactly which business problems were solved - -### Example: Bad vs. Good Impact Measurement - -**Without Tracing (Bad):** -``` -Safe output: PR #456 merged -PR labels: none -Conclusion: No impact (objectiveValue = 0) -``` - -**With Tracing (Good):** -``` -Safe output: PR #456 merged -PR linked to: Issue #123 "Fix auth token expiry" -Issue #123 labels: epic-auth, critical -Conclusion: 100 impact points delivered (from critical label) -Portfolio: "We delivered a critical fix to the auth epic" -``` - -## Data: How Objectives Should Be Assigned - -PMs assign objectives by labeling root issues/epics. Examples: - -| Root Object | Labels | Impact | Meaning | -|---|---|---|---| -| Issue #1234 | `epic-auth` | 500 | Work toward major auth initiative | -| Issue #5678 | `critical` | 100 | Must-fix bug blocking users | -| Issue #9012 | `p1` | 50 | Important enhancement | -| Epic "Modernize API" | `initiative-api-v2` | 1000 | Major multi-quarter initiative | - -When a PR closes one of these issues, it inherits the impact value. - -## API & Functions - -### ObjectiveMapping - -```go -type ObjectiveMapping struct { - LabelToValue map[string]int `json:"label_to_value"` - MultiLabelLogic string `json:"multi_label_logic"` - PriorityLabels []string `json:"priority_labels"` -} - -// Compute value from labels using configured strategy -func (om *ObjectiveMapping) ComputeObjectiveValue(labels []string) int - -// Get objective labels (mapped labels only) -func (om *ObjectiveMapping) GetObjectiveLabels(labels []string) []string - -// Load from config file, env var, or defaults -func LoadObjectiveMappingFromConfig() *ObjectiveMapping - -// Get built-in defaults -func DefaultObjectiveMapping() *ObjectiveMapping -``` - -### Objective Breakdown - -```go -type DomainBreakdown struct { - Label string `json:"label"` // Objective label (e.g., "epic-auth") - Attempted int `json:"attempted"` // Count of work toward this objective - Accepted int `json:"accepted"` // Count successfully delivered - Rejected int `json:"rejected"` // Count that failed - Pending int `json:"pending"` // Count in progress - TotalObjectiveValue int `json:"total_objective_value"` // Impact attempted - AcceptedObjectiveValue int `json:"accepted_objective_value"` // Impact delivered - ObjectiveEfficiency float64 `json:"objective_efficiency"` // Efficiency % - AcceptanceRate float64 `json:"acceptance_rate"` // Success % -} - -// Aggregate outcomes by objective label -func ComputeDomainBreakdowns(reports []OutcomeReport) []DomainBreakdown -``` - -## Testing - -### Unit Tests - -The `label_objective_mapping_test.go` covers: - -- Max/sum/first combination logics with multiple label scenarios -- Case insensitivity and whitespace trimming -- Nil and empty slice handling -- Combined label computation -- Real-world scenarios (e.g., `[bug, p0]`, `[performance, workflow]`) - -All tests must pass before deployment: - -```bash -go test ./pkg/github -run TestObjectiveMapping -go test ./pkg/cli -run "TestComputeOutcomeSummary|TestEvaluateOutcomes" -``` - -### Current Integration Tests - -Current tests verify: - -1. Objective values are computed with the configured combination strategy -2. Pull request outcomes trace to closing issues before label evaluation -3. Direct issue-label fallback works when PR tracing is unavailable -4. Objective summaries and breakdowns aggregate correctly -5. Audit trail (`traced_root_url`) is recorded correctly - -### Future Integration Tests - -Additional end-to-end testing should verify: - -1. Root tracing correctly follows PR → issue → epic links once epic support exists -2. Labels fetched from final root objects, not from intermediate artifacts -3. Cost-aware efficiency metrics calculate accurately when AI Credits data is available - -## Extended Performance Considerations - -1. **Mapping Loaded Once** — At CLI startup, reused for all outcomes -2. **GitHub API Calls** — One call per outcome to fetch labels (async batch recommended) -3. **Aggregation** — O(n) scan of outcomes to compute domains -4. **Memory** — Domain map is O(unique labels), typically < 100 entries - -## Error Handling - -| Error | Behavior | Recovery | -|-------|----------|----------| -| Missing config file | Use defaults | Application continues | -| Invalid JSON in config | Use defaults, log error | Application continues | -| GitHub API 404 | Skip enrichment, value = 0 | Outcome evaluates normally | -| GitHub API 5xx | Log error, skip enrichment | Retry on next evaluation cycle | -| Invalid label in config | Ignored | Mapping continues with valid labels | - -## Future Extensions - -1. **Batch Root Tracing** — Async batch fetching of root issues to reduce GitHub API rate limits -2. **Impact Trends** — Track efficiency trends over time (e.g., "epic-auth efficiency improved from 60% to 75%") -3. **Multi-Issue Links** — Handle PRs linked to multiple issues with different objectives -4. **Epic Hierarchies** — Support nested epics (epic → parent epic → get labels from both) -5. **Workflowized Portfolio Reports** — Dedicated reporting workflows built on the existing objective-enriched outcome data -6. **AI Credits Integration** — Factor in real run-cost data for value-per-credit reporting -7. **Predictive Efficiency** — Use historical efficiency to forecast likely delivery rate - -## References - -- [Safe Output Outcome Evaluation Specification](./safe-output-outcome-evaluation.md) -- [AI Credits Specification](../docs/src/content/docs/specs/ai-credits-specification.md) -- Implementation: `pkg/github/label_objective_mapping.go`, `pkg/cli/outcome_domain_breakdown.go` From 913511238d62942a78dcd20af8f6d553e1abdca2 Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer <8320933+mnkiefer@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:03:35 +0200 Subject: [PATCH 2/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- specs/intent-attribution-agent-governance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/intent-attribution-agent-governance.md b/specs/intent-attribution-agent-governance.md index 6a2a596598a..0095a785d94 100644 --- a/specs/intent-attribution-agent-governance.md +++ b/specs/intent-attribution-agent-governance.md @@ -6,7 +6,7 @@ status: Partially Implemented date: 2026-06-09 last_updated: 2026-06-12 replaces: objective-mapping-portfolio-reporting.md --------------------------------------------------- +--- # Intent Attribution & Agent Governance Specification From 90937dbcccb31b37d16ed29685c3ceb2831a0764 Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer <8320933+mnkiefer@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:04:11 +0200 Subject: [PATCH 3/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pkg/intent/resolver.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/intent/resolver.go b/pkg/intent/resolver.go index 28c934de236..53005a5bccc 100644 --- a/pkg/intent/resolver.go +++ b/pkg/intent/resolver.go @@ -85,7 +85,16 @@ func (r Resolver) ResolveIssue(nodeID, url string, labels []string) IntentRecord if len(labels) == 0 { return r.unlinked("no_supported_intent_source") } - return r.fromLabels(nodeID, url, labels, SourceIssueLabels, "issue_label_fallback") + return IntentRecord{ + Status: r.statusForLabels(labels), + Source: SourceIssueLabels, + RootNodeID: nodeID, + RootType: "issue", + RootURL: url, + Labels: cloneStrings(labels), + Rule: "issue_label_fallback", + ResolverVersion: r.ResolverVersion, + } } func (r Resolver) fromRoot(root RootReference, source AttributionSource, rule string) IntentRecord { From 4b0f4a2ac45be26dd54228fe543be7ce2a13a279 Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer <8320933+mnkiefer@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:04:44 +0200 Subject: [PATCH 4/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- pkg/cli/outcome_eval.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/cli/outcome_eval.go b/pkg/cli/outcome_eval.go index 4a0162fa060..648a4340db6 100644 --- a/pkg/cli/outcome_eval.go +++ b/pkg/cli/outcome_eval.go @@ -517,9 +517,10 @@ func loadPullRequestIntentData(report OutcomeReport, repo string) (intent.PullRe nodes, _ := closingRefs["nodes"].([]any) if len(nodes) == 0 { labels, labelErr := objectiveMappingGHAPIGetArray(fmt.Sprintf("issues/%d/labels", report.ObjectNumber), repo) - if labelErr == nil { - prData.Labels = labelsToStringsFromMaps(labels) + if labelErr != nil { + return intent.PullRequestData{}, labelErr } + prData.Labels = labelsToStringsFromMaps(labels) return prData, nil } From f5b2f824a39de464c59d79125ae93292a7bb0dd6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 03:11:51 +0000 Subject: [PATCH 5/9] Merge origin/main into improve-outcome-resolver Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/assign_agent_helpers.test.cjs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/assign_agent_helpers.test.cjs b/actions/setup/js/assign_agent_helpers.test.cjs index b8e7f7875a0..cefd89b2d63 100644 --- a/actions/setup/js/assign_agent_helpers.test.cjs +++ b/actions/setup/js/assign_agent_helpers.test.cjs @@ -17,9 +17,8 @@ const mockGithub = { globalThis.core = mockCore; globalThis.github = mockGithub; -const { AGENT_LOGIN_NAMES, getAgentName, getAvailableAgentLogins, findAgent, getIssueDetails, getPullRequestDetails, assignAgentToIssue, generatePermissionErrorSummary, assignAgentToIssueByName } = await import( - "./assign_agent_helpers.cjs" -); +const { AGENT_LOGIN_NAMES, getAgentName, getAvailableAgentLogins, findAgent, getIssueDetails, getPullRequestDetails, assignAgentToIssue, generatePermissionErrorSummary, assignAgentToIssueByName } = + await import("./assign_agent_helpers.cjs"); describe("assign_agent_helpers.cjs", () => { beforeEach(() => { From e775c7a4e56a1d4db4d0ad6934b89e578fd13483 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 03:19:23 +0000 Subject: [PATCH 6/9] Fix TestResolverResolveIssueMapped to expect RootType "issue" not "artifact" Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- pkg/intent/resolver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/intent/resolver_test.go b/pkg/intent/resolver_test.go index 660e2e99143..307f4070978 100644 --- a/pkg/intent/resolver_test.go +++ b/pkg/intent/resolver_test.go @@ -113,6 +113,6 @@ func TestResolverResolveIssueMapped(t *testing.T) { assert.Equal(t, AttributionMapped, intent.Status) assert.Equal(t, SourceIssueLabels, intent.Source) assert.Equal(t, "issue_label_fallback", intent.Rule) - assert.Equal(t, "artifact", intent.RootType) + assert.Equal(t, "issue", intent.RootType) assert.Equal(t, []string{"documentation"}, intent.Labels) } From 6ed33f30fd0df0174c66fe1b8f4b94cb16350ca3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 03:35:55 +0000 Subject: [PATCH 7/9] Changes before error encountered Agent-Logs-Url: https://github.com/github/gh-aw/sessions/145b93b5-a658-47fb-bd00-703e7adace08 Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- .github/workflows/release.lock.yml | 3 +- .../smoke-copilot-aoai-entra.lock.yml | 321 +++++++++++------- 2 files changed, 193 insertions(+), 131 deletions(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 88986810e83..7791bb048ba 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -661,7 +661,8 @@ jobs: "required": true, "type": "string", "sanitize": true, - "maxLength": 65000 + "maxLength": 65000, + "minLength": 20 }, "operation": { "required": true, diff --git a/.github/workflows/smoke-copilot-aoai-entra.lock.yml b/.github/workflows/smoke-copilot-aoai-entra.lock.yml index 4b991a5c414..b956d54065f 100644 --- a/.github/workflows/smoke-copilot-aoai-entra.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-entra.lock.yml @@ -1,5 +1,7 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"aba61bc550265ab03dbf7a4c1c330fbe8dee427169fa180fe08975529ea0026b","body_hash":"544a4bb8ccad1f2b14e10c580fbd23705eb8196559fb5606a048c9f8415a9b0c","agent_id":"copilot","agent_model":"o4-mini-aw","engine_versions":{"copilot":"1.0.60"}} -# gh-aw-manifest: {"version":1,"secrets":["FOUNDRY_OPENAI_ENDPOINT","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.2","digest":"sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.2@sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"},{"image":"ghcr.io/github/serena-mcp-server:latest","digest":"sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5","pinned_image":"ghcr.io/github/serena-mcp-server:latest@sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"aba61bc550265ab03dbf7a4c1c330fbe8dee427169fa180fe08975529ea0026b","body_hash":"28391c920f1e2f0de620798cc3026b8a4ab4412ee5a9d9d0a158f5a06fc976f5","agent_id":"copilot","agent_model":"o4-mini-aw","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-manifest: {"version":1,"secrets":["FOUNDRY_OPENAI_ENDPOINT","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4","digest":"sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4","digest":"sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4","digest":"sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4@sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4","digest":"sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.26","digest":"sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.3.0","digest":"sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80","pinned_image":"ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80"},{"image":"ghcr.io/github/serena-mcp-server:latest","digest":"sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5","pinned_image":"ghcr.io/github/serena-mcp-server:latest@sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5"}]} +# This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md +# # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +16,6 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw. DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -57,12 +58,13 @@ # - docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 -# - ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.2@sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0 -# - ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 -# - ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa -# - ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c +# - ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd +# - ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4@sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545 +# - ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 +# - ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 +# - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b +# - ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 # - ghcr.io/github/serena-mcp-server:latest@sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5 name: "Smoke Copilot - AOAI (Entra)" @@ -85,7 +87,7 @@ run-name: "Smoke Copilot - AOAI (Entra)" env: OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_OTEL_SENTRY_ENDPOINT }} OTEL_SERVICE_NAME: gh-aw.smoke-copilot-aoai-entra - OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Smoke Copilot - AOAI (Entra),gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot' + OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Smoke%20Copilot%20-%20AOAI%20%28Entra%29,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot' OTEL_EXPORTER_OTLP_HEADERS: x-sentry-auth=${{ secrets.GH_AW_OTEL_SENTRY_AUTHORIZATION }} GH_AW_OTLP_ALL_HEADERS: x-sentry-auth=${{ secrets.GH_AW_OTEL_SENTRY_AUTHORIZATION }},Authorization=${{ secrets.GH_AW_OTEL_GRAFANA_AUTHORIZATION }} GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_OTEL_SENTRY_ENDPOINT }}","headers":"x-sentry-auth=${{ secrets.GH_AW_OTEL_SENTRY_AUTHORIZATION }}"},{"url":"${{ secrets.GH_AW_OTEL_GRAFANA_ENDPOINT }}","headers":"Authorization=${{ secrets.GH_AW_OTEL_GRAFANA_AUTHORIZATION }}"}]' @@ -147,8 +149,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" @@ -158,15 +160,15 @@ jobs: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: "o4-mini-aw" - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AGENT_VERSION: "1.0.60" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AGENT_VERSION: "1.0.63" GH_AW_INFO_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["*.grafana.net","*.sentry.io","defaults","github","login.microsoftonline.com","node","playwright"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_INFO_FRONTMATTER_EMOJI: "🧪" @@ -178,6 +180,30 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); + - name: Restore daily AIC usage cache + id: restore-daily-aic-cache + if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} + continue-on-error: true + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-smokecopilotaoaientra-${{ github.run_id }} + restore-keys: agentic-workflow-usage-smokecopilotaoaientra- + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Restore daily AIC usage cache (artifact fallback) + id: restore-daily-aic-cache-fallback + if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_RESTORE_DAILY_AIC_CACHE_HIT: ${{ steps.restore-daily-aic-cache.outputs.cache-hit }} + GH_AW_RESTORE_DAILY_AIC_CACHE_MATCHED_KEY: ${{ steps.restore-daily-aic-cache.outputs.cache-matched-key }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/restore_aic_usage_cache_fallback.cjs'); + await main(); - name: Check daily workflow token guardrail id: daily-effective-workflow-guardrail if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} @@ -187,6 +213,8 @@ jobs: GH_AW_WORKFLOW_ID: "smoke-copilot-aoai-entra" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }} + GH_AW_HAS_SLASH_COMMAND: "true" + GH_AW_HAS_LABEL_COMMAND: "true" GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} with: @@ -337,25 +365,25 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_32194ed40fd02c9a_EOF' + cat << 'GH_AW_PROMPT_9d9b05f821ba5ebb_EOF' - GH_AW_PROMPT_32194ed40fd02c9a_EOF + GH_AW_PROMPT_9d9b05f821ba5ebb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/playwright_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_32194ed40fd02c9a_EOF' + cat << 'GH_AW_PROMPT_9d9b05f821ba5ebb_EOF' Tools: add_comment(max:2), create_issue, create_discussion, create_pull_request_review_comment(max:5), submit_pull_request_review, reply_to_pull_request_review_comment(max:5), add_labels, remove_labels, create_check_run, set_issue_type, dispatch_workflow, missing_tool, missing_data, noop, send_slack_message - GH_AW_PROMPT_32194ed40fd02c9a_EOF + GH_AW_PROMPT_9d9b05f821ba5ebb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_comment_memory.md" - cat << 'GH_AW_PROMPT_32194ed40fd02c9a_EOF' + cat << 'GH_AW_PROMPT_9d9b05f821ba5ebb_EOF' - GH_AW_PROMPT_32194ed40fd02c9a_EOF + GH_AW_PROMPT_9d9b05f821ba5ebb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_32194ed40fd02c9a_EOF' + cat << 'GH_AW_PROMPT_9d9b05f821ba5ebb_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -384,12 +412,12 @@ jobs: {{/if}} - GH_AW_PROMPT_32194ed40fd02c9a_EOF + GH_AW_PROMPT_9d9b05f821ba5ebb_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md" if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md" fi - cat << 'GH_AW_PROMPT_32194ed40fd02c9a_EOF' + cat << 'GH_AW_PROMPT_9d9b05f821ba5ebb_EOF' {{#runtime-import .github/workflows/shared/github-guard-policy.md}} {{#runtime-import .github/workflows/shared/gh.md}} @@ -399,36 +427,10 @@ jobs: {{#runtime-import .github/workflows/shared/otlp.md}} ## Serena Code Analysis - The Serena MCP server is configured for **["go"]** analysis in this workspace: - - **Workspace**: `__GH_AW_GITHUB_WORKSPACE__` - - **Memory**: `/tmp/gh-aw/cache-memory/serena/` - - ### Project Activation - - Before analyzing code, activate the Serena project: - ``` - Tool: activate_project - Args: { "path": "__GH_AW_GITHUB_WORKSPACE__" } - ``` - - ### Available Capabilities - - Serena provides IDE-grade Language Server Protocol (LSP) tools including: - - **Symbol search**: `find_symbol` — locate functions, types, interfaces by name - - **Navigation**: `find_referencing_symbols` — find all callers/usages of a symbol - - **Type info**: `get_symbol_documentation` — hover-level type and doc information - - **Code editing**: `replace_symbol_body`, `insert_after_symbol` — symbol-level edits - - **Diagnostics**: `get_diagnostics` — compiler errors and linter warnings - - ### Analysis Guidelines - - 1. **Use semantic tools over text search** — prefer Serena's LSP tools over `grep` - 2. **Activate project first** — always call `activate_project` before other tools - 3. **Cross-reference findings** — validate with multiple tools for accuracy - 4. **Focus on the relevant language files** — ignore unrelated file types + Serena is enabled for **["go"]** in `__GH_AW_GITHUB_WORKSPACE__`. Start by calling `activate_project` with that workspace path, then prefer Serena semantic tools for symbol lookup, references, docs, diagnostics, and structured edits. {{#runtime-import .github/workflows/shared/noop-reminder.md}} {{#runtime-import .github/workflows/smoke-copilot-aoai-entra.md}} - GH_AW_PROMPT_32194ed40fd02c9a_EOF + GH_AW_PROMPT_9d9b05f821ba5ebb_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -554,6 +556,8 @@ jobs: ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }} aic: ${{ steps.parse-mcp-gateway.outputs.aic }} ambient_context: ${{ steps.parse-mcp-gateway.outputs.ambient_context }} + cache_memory_restore_0_cache_hit: ${{ steps.restore_cache_memory_0.outputs.cache-hit || 'false' }} + cache_memory_restore_0_matched_key: ${{ steps.restore_cache_memory_0.outputs.cache-matched-key || '' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} has_patch: ${{ steps.collect_output.outputs.has_patch }} @@ -586,8 +590,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths @@ -650,6 +654,7 @@ jobs: - name: Create cache-memory directory run: bash "${RUNNER_TEMP}/gh-aw/actions/create_cache_memory_dir.sh" - name: Restore cache-memory file share data + id: restore_cache_memory_0 uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: key: memory-approved-a3cea483-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} @@ -689,13 +694,13 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.4 - name: Install Playwright CLI - run: npm install -g @playwright/cli@0.1.13 + run: npm install -g @playwright/cli@0.1.14 env: NPM_CONFIG_MIN_RELEASE_AGE: '3' timeout-minutes: 10 @@ -743,7 +748,7 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.2@sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c ghcr.io/github/serena-mcp-server:latest@sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4@sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545 ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 ghcr.io/github/serena-mcp-server:latest@sha256:bf343399e3725c45528f531a230f3a04521d4cdef29f9a5af6282ff0d3c393c5 - name: Build and install gh-aw CLI from source run: | gh extension remove aw || true @@ -1180,46 +1185,6 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); await main(); - - name: Generate Safe Outputs MCP Server Config - id: safe-outputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - # Mask immediately to prevent timing vulnerabilities - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${API_KEY}" - - PORT=3001 - - # Set outputs for next steps - { - echo "safe_outputs_api_key=${API_KEY}" - echo "safe_outputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Outputs MCP server will run on port ${PORT}" - - - name: Start Safe Outputs MCP HTTP Server - id: safe-outputs-start - env: - DEBUG: '*' - GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_OUTPUTS - export GH_AW_SAFE_OUTPUTS_PORT - export GH_AW_SAFE_OUTPUTS_API_KEY - export GH_AW_SAFE_OUTPUTS_TOOLS_PATH - export GH_AW_SAFE_OUTPUTS_CONFIG_PATH - export GH_AW_MCP_LOG_DIR - - bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh" - - name: Write MCP Scripts Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-scripts/logs" @@ -1686,8 +1651,8 @@ jobs: GH_AW_MCP_SCRIPTS_API_KEY: ${{ steps.mcp-scripts-start.outputs.api_key }} GH_AW_MCP_SCRIPTS_PORT: ${{ steps.mcp-scripts-start.outputs.port }} GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -1716,11 +1681,11 @@ jobs: * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; esac DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_MCP_SCRIPTS_PORT -e GH_AW_MCP_SCRIPTS_API_KEY -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -e GH_TOKEN -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.25' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e GH_AW_MCP_SCRIPTS_PORT -e GH_AW_MCP_SCRIPTS_API_KEY -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -e GH_TOKEN -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.26' mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_51d567a2fd4f7ca5_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_725950850813ed76_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "agenticworkflows": { @@ -1757,10 +1722,27 @@ jobs: } }, "safeoutputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", - "headers": { - "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + "type": "stdio", + "container": "ghcr.io/github/gh-aw-node", + "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw/mcp-logs/safeoutputs:/tmp/gh-aw/mcp-logs/safeoutputs:rw"], + "args": ["-w", "\${GITHUB_WORKSPACE}"], + "entrypoint": "sh", + "entrypointArgs": ["-c", "exec node ${RUNNER_TEMP}/gh-aw/safeoutputs/safe_outputs_mcp_server.cjs"], + "env": { + "DEBUG": "*", + "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}", + "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}", + "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}", + "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}", + "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}", + "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", + "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", + "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", + "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", + "GITHUB_SERVER_URL": "\${GITHUB_SERVER_URL}", + "GITHUB_TOKEN": "\${GITHUB_TOKEN}", + "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", + "RUNNER_TEMP": "\${RUNNER_TEMP}" }, "guard-policies": { "write-sink": { @@ -1812,7 +1794,7 @@ jobs: } } } - GH_AW_MCP_CONFIG_51d567a2fd4f7ca5_EOF + GH_AW_MCP_CONFIG_725950850813ed76_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -1839,7 +1821,7 @@ jobs: GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} GITHUB_SERVER_URL: ${{ github.server_url }} CLI_PROXY_POLICY: '{"allow-only":{"min-integrity":"approved","repos":"all"}}' - CLI_PROXY_IMAGE: 'ghcr.io/github/gh-aw-mcpg:v0.3.25' + CLI_PROXY_IMAGE: 'ghcr.io/github/gh-aw-mcpg:v0.3.26' run: | bash "${RUNNER_TEMP}/gh-aw/actions/start_cli_proxy.sh" - name: Execute GitHub Copilot CLI @@ -1859,13 +1841,30 @@ jobs: export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.githubusercontent.com\",\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"cdn.playwright.dev\",\"codeload.github.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"docs.github.com\",\"esm.sh\",\"get.pnpm.io\",\"github-cloud.githubusercontent.com\",\"github-cloud.s3.amazonaws.com\",\"github.blog\",\"github.com\",\"github.githubassets.com\",\"go.dev\",\"golang.org\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"goproxy.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"lfs.github.com\",\"login.microsoftonline.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"objects.githubusercontent.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"patch-diff.githubusercontent.com\",\"pkg.go.dev\",\"playwright.download.prss.microsoft.com\",\"ppa.launchpad.net\",\"proxy.golang.org\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"sum.golang.org\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.4/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.githubusercontent.com\",\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"cdn.playwright.dev\",\"codeload.github.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"docs.github.com\",\"esm.sh\",\"get.pnpm.io\",\"github-cloud.githubusercontent.com\",\"github-cloud.s3.amazonaws.com\",\"github.blog\",\"github.com\",\"github.githubassets.com\",\"go.dev\",\"golang.org\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"goproxy.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"lfs.github.com\",\"login.microsoftonline.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"objects.githubusercontent.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"patch-diff.githubusercontent.com\",\"pkg.go.dev\",\"playwright.download.prss.microsoft.com\",\"ppa.launchpad.net\",\"proxy.golang.org\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"sum.golang.org\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.4,squid=sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8,agent=sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a,api-proxy=sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd,cli-proxy=sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" + GH_AW_DOCKER_HOST="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST="${DOCKER_HOST}" + fi GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + python3 - <<'PY' + import json,os,subprocess as sp + from pathlib import Path + try: + p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" + c=json.loads(p.read_text()) + c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} + out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" + p.write_text(out) + Path("/tmp/gh-aw/awf-config.json").write_text(out) + except Exception as e: + raise SystemExit(f"chroot config patch failed: {e}") from e + PY fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" @@ -1877,7 +1876,7 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts:${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts:rw" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_PROVIDER_BASE_URL --exclude-env GH_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull --difc-proxy-host host.docker.internal:18443 --difc-proxy-ca-cert /tmp/gh-aw/difc-proxy-tls/ca.crt \ + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts:${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts:rw" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_PROVIDER_BASE_URL --exclude-env GH_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull --difc-proxy-host host.docker.internal:18443 --difc-proxy-ca-cert /tmp/gh-aw/difc-proxy-tls/ca.crt \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --autopilot --max-autopilot-continues 2 --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --no-custom-instructions --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_AUTH_AZURE_CLIENT_ID: adb907fd-188c-4029-b67f-2559d96b2f1b @@ -1890,6 +1889,7 @@ jobs: COPILOT_MODEL: o4-mini-aw COPILOT_PROVIDER_BASE_URL: ${{ secrets.FOUNDRY_OPENAI_ENDPOINT }} COPILOT_PROVIDER_WIRE_API: responses + GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -1911,6 +1911,7 @@ jobs: GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} + TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - name: Stop CLI Proxy if: always() continue-on-error: true @@ -2175,8 +2176,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -2226,6 +2227,45 @@ jobs: /tmp/gh-aw/usage/agent/token_usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl if-no-files-found: ignore + - name: Restore daily AIC usage cache + id: restore-daily-aic-cache-conclusion + if: always() + continue-on-error: true + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-smokecopilotaoaientra-${{ github.run_id }} + restore-keys: agentic-workflow-usage-smokecopilotaoaientra- + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Write daily AIC usage cache entry + id: write-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + github-token: ${{ github.token }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context); + const { main } = require('${{ runner.temp }}/gh-aw/actions/write_daily_aic_usage_cache.cjs'); + await main(); + - name: Save daily AIC usage cache + id: save-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-smokecopilotaoaientra-${{ github.run_id }} + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Upload daily AIC usage cache artifact + id: upload-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: aic-usage-cache + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + if-no-files-found: ignore + retention-days: 7 - name: Process no-op messages id: noop uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -2334,6 +2374,8 @@ jobs: GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" GH_AW_TIMEOUT_MINUTES: "15" GH_AW_CACHE_MEMORY_ENABLED: "true" + GH_AW_CACHE_MEMORY_RESTORE_0_MATCHED_KEY: ${{ needs.agent.outputs.cache_memory_restore_0_matched_key || '' }} + GH_AW_CACHE_MEMORY_RESTORE_0_CACHE_HIT: ${{ needs.agent.outputs.cache_memory_restore_0_cache_hit || 'false' }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -2399,8 +2441,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -2433,7 +2475,7 @@ jobs: rm -rf /tmp/gh-aw/sandbox/firewall/logs rm -rf /tmp/gh-aw/sandbox/firewall/audit - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 - name: Check if detection needed id: detection_guard if: always() @@ -2496,11 +2538,11 @@ jobs: node-version: '24' package-manager-cache: false - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.4 - name: Execute GitHub Copilot CLI if: always() && steps.detection_guard.outputs.run_detection == 'true' continue-on-error: true @@ -2519,13 +2561,30 @@ jobs: export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) - GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.4/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"login.microsoftonline.com\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS}},\"container\":{\"imageTag\":\"0.27.4,squid=sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8,agent=sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a,api-proxy=sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd,cli-proxy=sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" + GH_AW_DOCKER_HOST="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST="${DOCKER_HOST}" + fi GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + python3 - <<'PY' + import json,os,subprocess as sp + from pathlib import Path + try: + p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" + c=json.loads(p.read_text()) + c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} + out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" + p.write_text(out) + Path("/tmp/gh-aw/awf-config.json").write_text(out) + except Exception as e: + raise SystemExit(f"chroot config patch failed: {e}") from e + PY fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" @@ -2537,7 +2596,7 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_PROVIDER_BASE_URL --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_PROVIDER_BASE_URL --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: AWF_AUTH_AZURE_CLIENT_ID: adb907fd-188c-4029-b67f-2559d96b2f1b @@ -2550,6 +2609,7 @@ jobs: COPILOT_MODEL: o4-mini-aw COPILOT_PROVIDER_BASE_URL: ${{ secrets.FOUNDRY_OPENAI_ENDPOINT }} COPILOT_PROVIDER_WIRE_API: responses + GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -2568,6 +2628,7 @@ jobs: GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} + TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - name: Parse threat detection token usage for step summary id: parse_detection_token_usage if: always() @@ -2652,8 +2713,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for command workflow id: check_membership @@ -2704,8 +2765,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -2784,7 +2845,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: "o4-mini-aw" - GH_AW_ENGINE_VERSION: "1.0.60" + GH_AW_ENGINE_VERSION: "1.0.63" GH_AW_PROJECT_UTC: "-08:00" GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 📰 *BREAKING: Report filed by [{workflow_name}]({run_url})*{ai_credits_suffix}{history_link}\",\"appendOnlyComments\":true,\"runStarted\":\"📰 BREAKING: [{workflow_name}]({run_url}) is now investigating this {event_type}. Sources say the story is developing...\",\"runSuccess\":\"📰 VERDICT: [{workflow_name}]({run_url}) has concluded. All systems operational. This is a developing story. 🎤\",\"runFailure\":\"📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident...\"}" GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} @@ -2825,8 +2886,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" @@ -2952,8 +3013,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Smoke Copilot - AOAI (Entra)" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/smoke-copilot-aoai-entra.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download cache-memory artifact (default) id: download_cache_default From facec52f59d0f1ef5e71d38dee551e8849179d4c Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer Date: Wed, 17 Jun 2026 05:48:06 +0200 Subject: [PATCH 8/9] Revert changes to `release.lock.yml` --- .github/workflows/release.lock.yml | 265 +++++++++-------------------- 1 file changed, 84 insertions(+), 181 deletions(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 7791bb048ba..150c857b898 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1,7 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"bcc81867ababc01c5ccd64f77086887ee3dc5e7ee9390b1e2512545af19f98d3","body_hash":"aa140612f479fcd10e0e5b235d50155141079ca27b6de32b4bdec847d1caec86","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/login-action","sha":"650006c6eb7dba73a995cc03b0b2d7f5ca915bee","version":"v4.2.0"},{"repo":"docker/metadata-action","sha":"80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9","version":"v6.1.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4","digest":"sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4","digest":"sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4","digest":"sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.26","digest":"sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.3.0","digest":"sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80","pinned_image":"ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80"}]} -# This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md -# +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"38a8b80fd29c89f2823f08fc3fe4f6b2072be4a312bae61eddf27d138256534a","body_hash":"aa140612f479fcd10e0e5b235d50155141079ca27b6de32b4bdec847d1caec86","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/login-action","sha":"650006c6eb7dba73a995cc03b0b2d7f5ca915bee","version":"v4.2.0"},{"repo":"docker/metadata-action","sha":"80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9","version":"v6.1.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -16,6 +14,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # +# This file was automatically generated by gh-aw. DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -41,8 +40,6 @@ # - GITHUB_TOKEN # # Custom actions used: -# - actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 # - actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -56,12 +53,11 @@ # - docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd -# - ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 -# - ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 -# - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b -# - ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 +# - ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 +# - ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 +# - ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa +# - ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c name: "Release" on: @@ -144,8 +140,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" @@ -155,15 +151,15 @@ jobs: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AGENT_VERSION: "1.0.63" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AGENT_VERSION: "1.0.60" GH_AW_INFO_WORKFLOW_NAME: "Release" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["*.grafana.net","*.sentry.io","defaults","github.github.com","node"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_INFO_FRONTMATTER_EMOJI: "🚀" @@ -175,30 +171,6 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - - name: Restore daily AIC usage cache - id: restore-daily-aic-cache - if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} - continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - key: agentic-workflow-usage-release-${{ github.run_id }} - restore-keys: agentic-workflow-usage-release- - path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl - - name: Restore daily AIC usage cache (artifact fallback) - id: restore-daily-aic-cache-fallback - if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} - continue-on-error: true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - GH_AW_RESTORE_DAILY_AIC_CACHE_HIT: ${{ steps.restore-daily-aic-cache.outputs.cache-hit }} - GH_AW_RESTORE_DAILY_AIC_CACHE_MATCHED_KEY: ${{ steps.restore-daily-aic-cache.outputs.cache-matched-key }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/restore_aic_usage_cache_fallback.cjs'); - await main(); - name: Check daily workflow token guardrail id: daily-effective-workflow-guardrail if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} @@ -208,8 +180,6 @@ jobs: GH_AW_WORKFLOW_ID: "release" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }} - GH_AW_HAS_SLASH_COMMAND: "false" - GH_AW_HAS_LABEL_COMMAND: "false" GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} with: @@ -461,8 +431,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths @@ -524,11 +494,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.4 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -560,7 +530,7 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -661,8 +631,7 @@ jobs: "required": true, "type": "string", "sanitize": true, - "maxLength": 65000, - "minLength": 20 + "maxLength": 65000 }, "operation": { "required": true, @@ -688,16 +657,55 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); await main(); + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh" + - name: Start MCP Gateway id: start-mcp-gateway env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" @@ -724,16 +732,16 @@ jobs: * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; esac DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.26' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.25' mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_bb37170c1adf0f3e_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_47abdffabf02619d_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.3.0", + "container": "ghcr.io/github/github-mcp-server:v1.1.2", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -748,27 +756,10 @@ jobs: } }, "safeoutputs": { - "type": "stdio", - "container": "ghcr.io/github/gh-aw-node", - "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw/mcp-logs/safeoutputs:/tmp/gh-aw/mcp-logs/safeoutputs:rw"], - "args": ["-w", "\${GITHUB_WORKSPACE}"], - "entrypoint": "sh", - "entrypointArgs": ["-c", "exec node ${RUNNER_TEMP}/gh-aw/safeoutputs/safe_outputs_mcp_server.cjs"], - "env": { - "DEBUG": "*", - "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}", - "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}", - "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}", - "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}", - "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}", - "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", - "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", - "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", - "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", - "GITHUB_SERVER_URL": "\${GITHUB_SERVER_URL}", - "GITHUB_TOKEN": "\${GITHUB_TOKEN}", - "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", - "RUNNER_TEMP": "\${RUNNER_TEMP}" + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" }, "guard-policies": { "write-sink": { @@ -791,7 +782,7 @@ jobs: } } } - GH_AW_MCP_CONFIG_bb37170c1adf0f3e_EOF + GH_AW_MCP_CONFIG_47abdffabf02619d_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -852,30 +843,13 @@ jobs: export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.4/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"github.com\",\"github.github.com\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.4,squid=sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8,agent=sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a,api-proxy=sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd,cli-proxy=sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}" + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"github.com\",\"github.github.com\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" - GH_AW_DOCKER_HOST="" - if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then - GH_AW_DOCKER_HOST="${DOCKER_HOST}" - fi GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" - python3 - <<'PY' - import json,os,subprocess as sp - from pathlib import Path - try: - p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" - c=json.loads(p.read_text()) - c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} - out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" - p.write_text(out) - Path("/tmp/gh-aw/awf-config.json").write_text(out) - except Exception as e: - raise SystemExit(f"chroot config patch failed: {e}") from e - PY fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" @@ -887,7 +861,7 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(awk)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(gh issue list)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(mkdir)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sed)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 @@ -895,7 +869,6 @@ jobs: COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -916,7 +889,6 @@ jobs: GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} - TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - name: Detect agent errors if: always() id: detect-agent-errors @@ -1130,8 +1102,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1181,45 +1153,6 @@ jobs: /tmp/gh-aw/usage/agent/token_usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl if-no-files-found: ignore - - name: Restore daily AIC usage cache - id: restore-daily-aic-cache-conclusion - if: always() - continue-on-error: true - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - key: agentic-workflow-usage-release-${{ github.run_id }} - restore-keys: agentic-workflow-usage-release- - path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl - - name: Write daily AIC usage cache entry - id: write-daily-aic-cache - if: always() - continue-on-error: true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ github.token }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context); - const { main } = require('${{ runner.temp }}/gh-aw/actions/write_daily_aic_usage_cache.cjs'); - await main(); - - name: Save daily AIC usage cache - id: save-daily-aic-cache - if: always() - continue-on-error: true - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - key: agentic-workflow-usage-release-${{ github.run_id }} - path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl - - name: Upload daily AIC usage cache artifact - id: upload-daily-aic-cache - if: always() - continue-on-error: true - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: aic-usage-cache - path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl - if-no-files-found: ignore - retention-days: 7 - name: Process no-op messages id: noop uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1501,41 +1434,11 @@ jobs: } # Update Defender signatures before scanning. - $signatureUpdateAttempts = 3 - $signatureUpdateDelaySeconds = 15 - $signatureUpdateSucceeded = $false - $signatureUpdateExitCode = 1 - $mpCmdRunLogPaths = @( - (Join-Path $env:TEMP "MpCmdRun.log"), - (Join-Path $env:LOCALAPPDATA "Temp\MpCmdRun.log") - ) | Select-Object -Unique - for ($attemptNumber = 1; $attemptNumber -le $signatureUpdateAttempts; $attemptNumber++) { - Write-Host "Updating Microsoft Defender signatures (attempt $attemptNumber/$signatureUpdateAttempts)..." - & $mpCmdRun -SignatureUpdate - $signatureUpdateExitCode = $LASTEXITCODE - if ($signatureUpdateExitCode -eq 0) { - $signatureUpdateSucceeded = $true - break - } - - Write-Warning "Defender signature update attempt $attemptNumber failed with exit code $signatureUpdateExitCode" - foreach ($mpCmdRunLogPath in $mpCmdRunLogPaths) { - if (Test-Path $mpCmdRunLogPath) { - Write-Host "=== Tail of $mpCmdRunLogPath after attempt $attemptNumber ===" - Get-Content -Path $mpCmdRunLogPath -Tail 200 - } else { - Write-Host "MpCmdRun log file not found at $mpCmdRunLogPath" - } - } - - if ($attemptNumber -lt $signatureUpdateAttempts) { - Write-Host "Retrying Defender signature update in $signatureUpdateDelaySeconds seconds..." - Start-Sleep -Seconds $signatureUpdateDelaySeconds - } - } - if (-not $signatureUpdateSucceeded) { - Write-Error "Defender signature update failed after $signatureUpdateAttempts attempts (last exit code: $signatureUpdateExitCode)" - exit $signatureUpdateExitCode + Write-Host "Updating Microsoft Defender signatures..." + & $mpCmdRun -SignatureUpdate + if ($LASTEXITCODE -ne 0) { + Write-Error "Defender signature update failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE } # Log Defender status, preference, and execution details for diagnostics. @@ -1721,8 +1624,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for workflow id: check_membership @@ -1997,7 +1900,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.63" + GH_AW_ENGINE_VERSION: "1.0.60" GH_AW_PROJECT_UTC: "-08:00" GH_AW_WORKFLOW_EMOJI: "🚀" GH_AW_WORKFLOW_ID: "release" @@ -2029,8 +1932,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.63" - GH_AW_INFO_AWF_VERSION: "v0.27.4" + GH_AW_INFO_VERSION: "1.0.60" + GH_AW_INFO_AWF_VERSION: "v0.27.2" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" From d511aa1c93b47006d116207f8753fbd8a5b2cecb Mon Sep 17 00:00:00 2001 From: Mara Nikola Kiefer Date: Wed, 17 Jun 2026 05:50:50 +0200 Subject: [PATCH 9/9] revert file --- .github/workflows/release.lock.yml | 262 ++++++++++++++++++++--------- 1 file changed, 179 insertions(+), 83 deletions(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index d15d78a21e6..7791bb048ba 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -1,5 +1,7 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"38a8b80fd29c89f2823f08fc3fe4f6b2072be4a312bae61eddf27d138256534a","body_hash":"aa140612f479fcd10e0e5b235d50155141079ca27b6de32b4bdec847d1caec86","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/login-action","sha":"650006c6eb7dba73a995cc03b0b2d7f5ca915bee","version":"v4.2.0"},{"repo":"docker/metadata-action","sha":"80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9","version":"v6.1.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"bcc81867ababc01c5ccd64f77086887ee3dc5e7ee9390b1e2512545af19f98d3","body_hash":"aa140612f479fcd10e0e5b235d50155141079ca27b6de32b4bdec847d1caec86","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"anchore/sbom-action","sha":"e22c389904149dbc22b58101806040fa8d37a610","version":"v0.24.0"},{"repo":"docker/build-push-action","sha":"f9f3042f7e2789586610d6e8b85c8f03e5195baf","version":"v7.2.0"},{"repo":"docker/login-action","sha":"650006c6eb7dba73a995cc03b0b2d7f5ca915bee","version":"v4.2.0"},{"repo":"docker/metadata-action","sha":"80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9","version":"v6.1.0"},{"repo":"docker/setup-buildx-action","sha":"d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5","version":"v4.1.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4","digest":"sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4","digest":"sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4","digest":"sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.26","digest":"sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.3.0","digest":"sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80","pinned_image":"ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80"}]} +# This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md +# # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -14,7 +16,6 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw. DO NOT EDIT. # # To update this file, edit the corresponding .md file and run: # gh aw compile @@ -40,6 +41,8 @@ # - GITHUB_TOKEN # # Custom actions used: +# - actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 # - actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -53,11 +56,12 @@ # - docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 # # Container images used: -# - ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 -# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 -# - ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 -# - ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa -# - ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c +# - ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a +# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd +# - ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 +# - ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 +# - ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b +# - ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 name: "Release" on: @@ -140,8 +144,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" @@ -151,15 +155,15 @@ jobs: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AGENT_VERSION: "1.0.60" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AGENT_VERSION: "1.0.63" GH_AW_INFO_WORKFLOW_NAME: "Release" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" GH_AW_INFO_STAGED: "false" GH_AW_INFO_ALLOWED_DOMAINS: '["*.grafana.net","*.sentry.io","defaults","github.github.com","node"]' GH_AW_INFO_FIREWALL_ENABLED: "true" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_INFO_FRONTMATTER_EMOJI: "🚀" @@ -171,6 +175,30 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); + - name: Restore daily AIC usage cache + id: restore-daily-aic-cache + if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} + continue-on-error: true + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-release-${{ github.run_id }} + restore-keys: agentic-workflow-usage-release- + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Restore daily AIC usage cache (artifact fallback) + id: restore-daily-aic-cache-fallback + if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + GH_AW_RESTORE_DAILY_AIC_CACHE_HIT: ${{ steps.restore-daily-aic-cache.outputs.cache-hit }} + GH_AW_RESTORE_DAILY_AIC_CACHE_MATCHED_KEY: ${{ steps.restore-daily-aic-cache.outputs.cache-matched-key }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io, getOctokit); + const { main } = require('${{ runner.temp }}/gh-aw/actions/restore_aic_usage_cache_fallback.cjs'); + await main(); - name: Check daily workflow token guardrail id: daily-effective-workflow-guardrail if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} @@ -180,6 +208,8 @@ jobs: GH_AW_WORKFLOW_ID: "release" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }} + GH_AW_HAS_SLASH_COMMAND: "false" + GH_AW_HAS_LABEL_COMMAND: "false" GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} with: @@ -431,8 +461,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths @@ -494,11 +524,11 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.63 env: GH_HOST: github.com - name: Install AWF binary - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2 + run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.4 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -530,7 +560,7 @@ jobs: GH_AW_SKILL_DIR: ".github/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images - run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8 ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490 ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80 - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -658,55 +688,16 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs'); await main(); - - name: Generate Safe Outputs MCP Server Config - id: safe-outputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - # Mask immediately to prevent timing vulnerabilities - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${API_KEY}" - - PORT=3001 - - # Set outputs for next steps - { - echo "safe_outputs_api_key=${API_KEY}" - echo "safe_outputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Outputs MCP server will run on port ${PORT}" - - - name: Start Safe Outputs MCP HTTP Server - id: safe-outputs-start - env: - DEBUG: '*' - GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_OUTPUTS - export GH_AW_SAFE_OUTPUTS_PORT - export GH_AW_SAFE_OUTPUTS_API_KEY - export GH_AW_SAFE_OUTPUTS_TOOLS_PATH - export GH_AW_SAFE_OUTPUTS_CONFIG_PATH - export GH_AW_MCP_LOG_DIR - - bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh" - - name: Start MCP Gateway id: start-mcp-gateway env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" @@ -733,16 +724,16 @@ jobs: * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;; esac DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.25' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.26' mkdir -p "$HOME/.copilot" GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_47abdffabf02619d_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_bb37170c1adf0f3e_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v1.1.2", + "container": "ghcr.io/github/github-mcp-server:v1.3.0", "env": { "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", @@ -757,10 +748,27 @@ jobs: } }, "safeoutputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", - "headers": { - "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + "type": "stdio", + "container": "ghcr.io/github/gh-aw-node", + "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw/mcp-logs/safeoutputs:/tmp/gh-aw/mcp-logs/safeoutputs:rw"], + "args": ["-w", "\${GITHUB_WORKSPACE}"], + "entrypoint": "sh", + "entrypointArgs": ["-c", "exec node ${RUNNER_TEMP}/gh-aw/safeoutputs/safe_outputs_mcp_server.cjs"], + "env": { + "DEBUG": "*", + "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}", + "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}", + "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}", + "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}", + "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}", + "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", + "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", + "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", + "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", + "GITHUB_SERVER_URL": "\${GITHUB_SERVER_URL}", + "GITHUB_TOKEN": "\${GITHUB_TOKEN}", + "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", + "RUNNER_TEMP": "\${RUNNER_TEMP}" }, "guard-policies": { "write-sink": { @@ -783,7 +791,7 @@ jobs: } } } - GH_AW_MCP_CONFIG_47abdffabf02619d_EOF + GH_AW_MCP_CONFIG_bb37170c1adf0f3e_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -844,13 +852,30 @@ jobs: export GH_AW_NODE_BIN export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}" - printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"github.com\",\"github.github.com\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" + GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" + printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.4/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"*.grafana.net\",\"*.sentry.io\",\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"api.npms.io\",\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"bun.sh\",\"cdn.jsdelivr.net\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"deb.nodesource.com\",\"deno.land\",\"esm.sh\",\"get.pnpm.io\",\"github.com\",\"github.github.com\",\"googleapis.deno.dev\",\"googlechromelabs.github.io\",\"host.docker.internal\",\"json-schema.org\",\"json.schemastore.org\",\"jsr.io\",\"keyserver.ubuntu.com\",\"nodejs.org\",\"npm.pkg.github.com\",\"npmjs.com\",\"npmjs.org\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"raw.githubusercontent.com\",\"registry.bower.io\",\"registry.npmjs.com\",\"registry.npmjs.org\",\"registry.yarnpkg.com\",\"repo.yarnpkg.com\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"skimdb.npmjs.com\",\"storage.googleapis.com\",\"telemetry.enterprise.githubcopilot.com\",\"telemetry.vercel.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\",\"www.npmjs.com\",\"www.npmjs.org\",\"yarnpkg.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.4,squid=sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8,agent=sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a,api-proxy=sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd,cli-proxy=sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" + GH_AW_DOCKER_HOST="" + if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then + GH_AW_DOCKER_HOST="${DOCKER_HOST}" + fi GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" + python3 - <<'PY' + import json,os,subprocess as sp + from pathlib import Path + try: + p=Path(os.environ["RUNNER_TEMP"])/"gh-aw"/"awf-config.json" + c=json.loads(p.read_text()) + c["chroot"]={"binariesSourcePath":"/tmp/gh-aw","identity":{"user":sp.check_output(["id","-un"],text=True).strip(),"uid":int(sp.check_output(["id","-u"],text=True)),"gid":int(sp.check_output(["id","-g"],text=True)),"home":"/tmp/gh-aw/home"}} + out=json.dumps(c,separators=(",",":"),ensure_ascii=False)+"\n" + p.write_text(out) + Path("/tmp/gh-aw/awf-config.json").write_text(out) + except Exception as e: + raise SystemExit(f"chroot config patch failed: {e}") from e + PY fi GH_AW_TOOL_CACHE_MOUNT="" GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}" @@ -862,7 +887,7 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(awk)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(gh issue list)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(mkdir)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sed)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: AWF_REFLECT_ENABLED: 1 @@ -870,6 +895,7 @@ jobs: COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }} + GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -890,6 +916,7 @@ jobs: GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] RUNNER_TEMP: ${{ runner.temp }} + TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} - name: Detect agent errors if: always() id: detect-agent-errors @@ -1103,8 +1130,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1154,6 +1181,45 @@ jobs: /tmp/gh-aw/usage/agent/token_usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl if-no-files-found: ignore + - name: Restore daily AIC usage cache + id: restore-daily-aic-cache-conclusion + if: always() + continue-on-error: true + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-release-${{ github.run_id }} + restore-keys: agentic-workflow-usage-release- + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Write daily AIC usage cache entry + id: write-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + github-token: ${{ github.token }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context); + const { main } = require('${{ runner.temp }}/gh-aw/actions/write_daily_aic_usage_cache.cjs'); + await main(); + - name: Save daily AIC usage cache + id: save-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + key: agentic-workflow-usage-release-${{ github.run_id }} + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + - name: Upload daily AIC usage cache artifact + id: upload-daily-aic-cache + if: always() + continue-on-error: true + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: aic-usage-cache + path: /tmp/gh-aw/agentic-workflow-usage-cache.jsonl + if-no-files-found: ignore + retention-days: 7 - name: Process no-op messages id: noop uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1435,11 +1501,41 @@ jobs: } # Update Defender signatures before scanning. - Write-Host "Updating Microsoft Defender signatures..." - & $mpCmdRun -SignatureUpdate - if ($LASTEXITCODE -ne 0) { - Write-Error "Defender signature update failed with exit code $LASTEXITCODE" - exit $LASTEXITCODE + $signatureUpdateAttempts = 3 + $signatureUpdateDelaySeconds = 15 + $signatureUpdateSucceeded = $false + $signatureUpdateExitCode = 1 + $mpCmdRunLogPaths = @( + (Join-Path $env:TEMP "MpCmdRun.log"), + (Join-Path $env:LOCALAPPDATA "Temp\MpCmdRun.log") + ) | Select-Object -Unique + for ($attemptNumber = 1; $attemptNumber -le $signatureUpdateAttempts; $attemptNumber++) { + Write-Host "Updating Microsoft Defender signatures (attempt $attemptNumber/$signatureUpdateAttempts)..." + & $mpCmdRun -SignatureUpdate + $signatureUpdateExitCode = $LASTEXITCODE + if ($signatureUpdateExitCode -eq 0) { + $signatureUpdateSucceeded = $true + break + } + + Write-Warning "Defender signature update attempt $attemptNumber failed with exit code $signatureUpdateExitCode" + foreach ($mpCmdRunLogPath in $mpCmdRunLogPaths) { + if (Test-Path $mpCmdRunLogPath) { + Write-Host "=== Tail of $mpCmdRunLogPath after attempt $attemptNumber ===" + Get-Content -Path $mpCmdRunLogPath -Tail 200 + } else { + Write-Host "MpCmdRun log file not found at $mpCmdRunLogPath" + } + } + + if ($attemptNumber -lt $signatureUpdateAttempts) { + Write-Host "Retrying Defender signature update in $signatureUpdateDelaySeconds seconds..." + Start-Sleep -Seconds $signatureUpdateDelaySeconds + } + } + if (-not $signatureUpdateSucceeded) { + Write-Error "Defender signature update failed after $signatureUpdateAttempts attempts (last exit code: $signatureUpdateExitCode)" + exit $signatureUpdateExitCode } # Log Defender status, preference, and execution details for diagnostics. @@ -1625,8 +1721,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Check team membership for workflow id: check_membership @@ -1901,7 +1997,7 @@ jobs: GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.60" + GH_AW_ENGINE_VERSION: "1.0.63" GH_AW_PROJECT_UTC: "-08:00" GH_AW_WORKFLOW_EMOJI: "🚀" GH_AW_WORKFLOW_ID: "release" @@ -1933,8 +2029,8 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "Release" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.60" - GH_AW_INFO_AWF_VERSION: "v0.27.2" + GH_AW_INFO_VERSION: "1.0.63" + GH_AW_INFO_AWF_VERSION: "v0.27.4" GH_AW_INFO_ENGINE_ID: "copilot" - name: Mask OTLP telemetry headers run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"