From f1bdc4c5e931c30de25a5354763d14de505d7f39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 22:52:49 +0000 Subject: [PATCH 1/4] Initial plan From b149ca24df797fccf4c471ba3c3db8c5ea6c62d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 23:04:50 +0000 Subject: [PATCH 2/4] Document strict mode comprehensively in JSON schema and CLI help - Update main_workflow_schema.json `strict` field description to include: - All 5 enforcement areas: write permissions, network config, action pinning, MCP network, deprecated fields - CLI flag reference: `gh aw compile --strict` - Precedence rule: CLI flag takes precedence over frontmatter - Documentation link for detailed guidance - Update CLI help text for --strict flag to be more comprehensive - Schema validation passes, all tests pass - Verified with test workflows that strict mode works correctly Addresses issue githubnext/gh-aw#4193 per @pelikhan's feedback that the field is named "strict" in the schema. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- cmd/gh-aw/main.go | 2 +- pkg/parser/schemas/main_workflow_schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go index c27834153a..5371652bff 100644 --- a/cmd/gh-aw/main.go +++ b/cmd/gh-aw/main.go @@ -444,7 +444,7 @@ Use "` + constants.CLIExtensionPrefix + ` help all" to show help for all command _ = compileCmd.Flags().MarkDeprecated("workflows-dir", "use --dir instead") compileCmd.Flags().Bool("no-emit", false, "Validate workflow without generating lock files") compileCmd.Flags().Bool("purge", false, "Delete .lock.yml files that were not regenerated during compilation (only when no specific files are specified)") - compileCmd.Flags().Bool("strict", false, "Enable strict mode: require timeout, refuse write permissions, require network configuration") + compileCmd.Flags().Bool("strict", false, "Enable strict mode validation (enforces action pinning, network config, safe-outputs, refuses write permissions and deprecated fields)") compileCmd.Flags().Bool("trial", false, "Enable trial mode compilation (modifies workflows for trial execution)") compileCmd.Flags().String("logical-repo", "", "Repository to simulate workflow execution against (for trial mode)") compileCmd.Flags().Bool("dependabot", false, "Generate dependency manifests (package.json, requirements.txt, go.mod) and Dependabot config when dependencies are detected") diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index cc8e85b9d7..0c3f4f21af 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -3179,7 +3179,7 @@ }, "strict": { "type": "boolean", - "description": "Enable strict mode validation: require timeout, refuse write permissions, require network configuration. Defaults to false.", + "description": "Enable strict mode validation for enhanced security and compliance. Strict mode enforces: (1) Write Permissions - refuses contents:write, issues:write, pull-requests:write; requires safe-outputs instead, (2) Network Configuration - requires explicit network configuration with no wildcard '*' in allowed domains, (3) Action Pinning - enforces actions pinned to commit SHAs instead of tags/branches, (4) MCP Network - requires network configuration for custom MCP servers with containers, (5) Deprecated Fields - refuses deprecated frontmatter fields. Can be enabled per-workflow via 'strict: true' in frontmatter, or globally via CLI flag 'gh aw compile --strict' (CLI flag takes precedence over frontmatter). Defaults to false. See: https://githubnext.github.io/gh-aw/reference/frontmatter/#strict-mode-strict", "examples": [true] }, "runtimes": { From 45e142582078cc5d249a39a424d0d8b3dd56928d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 23:07:47 +0000 Subject: [PATCH 3/4] Add test to verify strict mode schema documentation completeness - Created schema_strict_documentation_test.go to verify the strict field description - Test validates presence of all 5 enforcement areas - Test verifies CLI flag reference and precedence rule - Test checks for documentation link - All tests pass successfully Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../schema_strict_documentation_test.go | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 pkg/parser/schema_strict_documentation_test.go diff --git a/pkg/parser/schema_strict_documentation_test.go b/pkg/parser/schema_strict_documentation_test.go new file mode 100644 index 0000000000..cdc08f6949 --- /dev/null +++ b/pkg/parser/schema_strict_documentation_test.go @@ -0,0 +1,74 @@ +package parser + +import ( +"encoding/json" +"os" +"strings" +"testing" +) + +// TestStrictFieldSchemaDocumentation verifies that the strict field in the schema +// contains comprehensive documentation about all enforcement areas and CLI usage +func TestStrictFieldSchemaDocumentation(t *testing.T) { +// Read the main workflow schema +schemaPath := "schemas/main_workflow_schema.json" +schemaContent, err := os.ReadFile(schemaPath) +if err != nil { +t.Fatalf("Failed to read schema file: %v", err) +} + +// Parse the schema +var schema map[string]interface{} +if err := json.Unmarshal(schemaContent, &schema); err != nil { +t.Fatalf("Failed to parse schema JSON: %v", err) +} + +// Get the properties section +properties, ok := schema["properties"].(map[string]interface{}) +if !ok { +t.Fatal("Schema properties section not found or invalid") +} + +// Get the strict field +strictField, ok := properties["strict"].(map[string]interface{}) +if !ok { +t.Fatal("Strict field not found in schema properties") +} + +// Get the description +description, ok := strictField["description"].(string) +if !ok { +t.Fatal("Strict field description not found or not a string") +} + +// Verify that description contains key elements +requiredElements := []string{ +"Write Permissions", +"Network Configuration", +"Action Pinning", +"MCP Network", +"Deprecated Fields", +"gh aw compile --strict", +"CLI flag takes precedence", +"safe-outputs", +} + +for _, element := range requiredElements { +if !strings.Contains(description, element) { +t.Errorf("Strict field description missing required element: %q\nDescription: %s", element, description) +} +} + +// Verify description contains documentation link +if !strings.Contains(description, "https://") { +t.Error("Strict field description should contain a documentation link") +} + +// Verify type is boolean +fieldType, ok := strictField["type"].(string) +if !ok || fieldType != "boolean" { +t.Errorf("Strict field type should be 'boolean', got: %v", fieldType) +} + +t.Logf("✓ Strict field description is comprehensive (%d chars)", len(description)) +} From 6dfdb0005f3109491434ae7513c23df8ebcaa9fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 23:24:46 +0000 Subject: [PATCH 4/4] Fix Go formatting in schema_strict_documentation_test.go - Applied gofmt to fix indentation - All tests pass - All linting checks pass Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../schema_strict_documentation_test.go | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/pkg/parser/schema_strict_documentation_test.go b/pkg/parser/schema_strict_documentation_test.go index cdc08f6949..b8194daa2d 100644 --- a/pkg/parser/schema_strict_documentation_test.go +++ b/pkg/parser/schema_strict_documentation_test.go @@ -1,74 +1,74 @@ package parser import ( -"encoding/json" -"os" -"strings" -"testing" + "encoding/json" + "os" + "strings" + "testing" ) // TestStrictFieldSchemaDocumentation verifies that the strict field in the schema // contains comprehensive documentation about all enforcement areas and CLI usage func TestStrictFieldSchemaDocumentation(t *testing.T) { -// Read the main workflow schema -schemaPath := "schemas/main_workflow_schema.json" -schemaContent, err := os.ReadFile(schemaPath) -if err != nil { -t.Fatalf("Failed to read schema file: %v", err) -} + // Read the main workflow schema + schemaPath := "schemas/main_workflow_schema.json" + schemaContent, err := os.ReadFile(schemaPath) + if err != nil { + t.Fatalf("Failed to read schema file: %v", err) + } -// Parse the schema -var schema map[string]interface{} -if err := json.Unmarshal(schemaContent, &schema); err != nil { -t.Fatalf("Failed to parse schema JSON: %v", err) -} + // Parse the schema + var schema map[string]interface{} + if err := json.Unmarshal(schemaContent, &schema); err != nil { + t.Fatalf("Failed to parse schema JSON: %v", err) + } -// Get the properties section -properties, ok := schema["properties"].(map[string]interface{}) -if !ok { -t.Fatal("Schema properties section not found or invalid") -} + // Get the properties section + properties, ok := schema["properties"].(map[string]interface{}) + if !ok { + t.Fatal("Schema properties section not found or invalid") + } -// Get the strict field -strictField, ok := properties["strict"].(map[string]interface{}) -if !ok { -t.Fatal("Strict field not found in schema properties") -} + // Get the strict field + strictField, ok := properties["strict"].(map[string]interface{}) + if !ok { + t.Fatal("Strict field not found in schema properties") + } -// Get the description -description, ok := strictField["description"].(string) -if !ok { -t.Fatal("Strict field description not found or not a string") -} + // Get the description + description, ok := strictField["description"].(string) + if !ok { + t.Fatal("Strict field description not found or not a string") + } -// Verify that description contains key elements -requiredElements := []string{ -"Write Permissions", -"Network Configuration", -"Action Pinning", -"MCP Network", -"Deprecated Fields", -"gh aw compile --strict", -"CLI flag takes precedence", -"safe-outputs", -} + // Verify that description contains key elements + requiredElements := []string{ + "Write Permissions", + "Network Configuration", + "Action Pinning", + "MCP Network", + "Deprecated Fields", + "gh aw compile --strict", + "CLI flag takes precedence", + "safe-outputs", + } -for _, element := range requiredElements { -if !strings.Contains(description, element) { -t.Errorf("Strict field description missing required element: %q\nDescription: %s", element, description) -} -} + for _, element := range requiredElements { + if !strings.Contains(description, element) { + t.Errorf("Strict field description missing required element: %q\nDescription: %s", element, description) + } + } -// Verify description contains documentation link -if !strings.Contains(description, "https://") { -t.Error("Strict field description should contain a documentation link") -} + // Verify description contains documentation link + if !strings.Contains(description, "https://") { + t.Error("Strict field description should contain a documentation link") + } -// Verify type is boolean -fieldType, ok := strictField["type"].(string) -if !ok || fieldType != "boolean" { -t.Errorf("Strict field type should be 'boolean', got: %v", fieldType) -} + // Verify type is boolean + fieldType, ok := strictField["type"].(string) + if !ok || fieldType != "boolean" { + t.Errorf("Strict field type should be 'boolean', got: %v", fieldType) + } -t.Logf("✓ Strict field description is comprehensive (%d chars)", len(description)) + t.Logf("✓ Strict field description is comprehensive (%d chars)", len(description)) }