Skip to content

Migrate workflow-plugin-cicd to strict gRPC proto contracts#2

Merged
intel352 merged 6 commits into
masterfrom
copilot/migrate-workflow-plugin-to-strict-grpc-contracts
May 6, 2026
Merged

Migrate workflow-plugin-cicd to strict gRPC proto contracts#2
intel352 merged 6 commits into
masterfrom
copilot/migrate-workflow-plugin-to-strict-grpc-contracts

Conversation

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor

The plugin advertised 31 step types and 1 module type with no typed schema declarations, causing wfctl strict contract audit to report 0/1 strict modules and 0/31 strict steps.

Changes

plugin.jsonstepSchemas for all 31 step types

Added a stepSchemas array covering every advertised step. Each entry declares typed configFields (key, type, required, default) and outputs (key, type, description). Output declarations for step.container_build and all deployment step types include the full set of runtime output keys (status, service, image, strategy, message) to match what deployStep.Execute() actually emits.

internal/plugin.goSchemaProvider for aws.codebuild

Implements sdk.SchemaProvider so the host engine receives a typed ModuleSchemaData descriptor for aws.codebuild via gRPC at startup, rather than having no descriptor at all:

func (p *cicdPlugin) ModuleSchemas() []sdk.ModuleSchemaData {
    return []sdk.ModuleSchemaData{{
        Type:        "aws.codebuild",
        Label:       "AWS CodeBuild",
        Category:    "CI/CD",
        Description: "...",
        ConfigFields: []sdk.ConfigField{
            {Name: "region",   Type: "string"},
            {Name: "role_arn", Type: "string"},
            {Name: "env_vars", Type: "map"},
        },
    }}
}

plugin.contracts.json (new)

Standalone audit artifact with "strict": true and explicit contract descriptors for all 32 types (1 module + 31 steps), consumable by wfctl audit plugins --strict-contracts tooling. Output declarations are accurate for all step types including step.container_build.

internal/plugin_test.go (new)

Tests enforcing contract completeness as code:

  • TestSchemaProvider — every module type has a schema
  • TestPluginJSONStepSchemasstepSchemas covers every declared step type
  • TestPluginContractsJSONplugin.contracts.json covers all types with strict: true and validates the contracts section, asserting every module/step type has a mode: "strict" entry
  • TestStepTypesConsistencyplugin.json capabilities and plugin binary agree exactly
  • TestShellExecStep and related — assert type assertions on output values succeed before comparing; Execute() calls use nil for the unused config parameter (config is set via CreateStep)

.github/workflows/ci.yml (new)

GitHub Actions CI workflow that runs on every PR and push to main/master with two jobs:

  • test — runs go test ./... to validate the full test suite
  • wfctl-strict-contracts — explicitly fails if plugin.json is missing, then runs go run github.com/GoCodeAlone/workflow/cmd/wfctl@v0.20.1 plugin validate --file plugin.json --strict-contracts to enforce strict contract compliance in CI

Both jobs use go-version-file: go.mod, GOWORK: "off", and private module URL rewrite consistent with the existing release.yml. A top-level permissions: contents: read block limits GITHUB_TOKEN scope.

Copilot AI changed the title [WIP] Migrate workflow-plugin-cicd to strict gRPC proto contracts Migrate workflow-plugin-cicd to strict gRPC proto contracts May 1, 2026
Copilot AI requested a review from intel352 May 1, 2026 06:20
@intel352 intel352 marked this pull request as ready for review May 1, 2026 06:24
@intel352 intel352 requested a review from Copilot May 1, 2026 06:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates workflow-plugin-cicd to “strict” contract declarations so host-side tooling (e.g., wfctl audits and schema-driven validation) can reason about module/step configuration and outputs instead of relying on untyped definitions.

Changes:

  • Adds stepSchemas entries to plugin.json covering all advertised step types.
  • Introduces plugin.contracts.json as a strict contract audit artifact covering all module + step types.
  • Implements sdk.SchemaProvider (ModuleSchemas) for aws.codebuild and adds tests enforcing contract completeness/consistency.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
plugin.json Adds stepSchemas for all declared step types with typed config fields + outputs.
plugin.contracts.json Adds strict audit contract descriptors for the module and all steps.
internal/plugin.go Adds ModuleSchemas() (SchemaProvider) for aws.codebuild and updates package documentation.
internal/plugin_test.go Adds tests to enforce schema/contract coverage and consistency between JSON artifacts and code.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/plugin_test.go Outdated
if output != "hello" {
t.Errorf("output = %q, want %q", output, "hello")
}
exitCode, _ := result.Output["exit_code"].(int)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d187e06. The shell_exec tests now assert the output and exit_code type assertions before checking values, so wrong output types fail the test instead of using zero values.

Comment thread plugin.json Outdated
Comment on lines +269 to +272
"description": "Checks out a Git branch, tag, or commit reference.",
"configFields": [
{"key": "ref", "label": "Ref", "type": "string", "description": "Git ref (branch, tag, or commit SHA) to check out", "required": true},
{"key": "branch", "label": "Branch", "type": "string", "description": "Alias for ref; used when ref is absent"},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d187e06. The manifest no longer marks ref as required for step.git_checkout and now documents that either ref or branch is required, matching runtime behavior.

Comment thread plugin.contracts.json Outdated
{
"type": "step.git_checkout",
"configFields": [
{"key": "ref", "type": "string", "required": true},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d187e06. The contract descriptor for step.git_checkout now treats ref as optional so branch-only configs are not rejected by strict contract validation.

@intel352

intel352 commented May 1, 2026

Copy link
Copy Markdown
Contributor

Validation after d187e06:

  • GOWORK=off go test ./... passed
  • GOWORK=off go vet ./... passed
  • GOWORK=off go test -race ./... passed
  • GOWORK=off go build ./cmd/workflow-plugin-cicd passed
  • GOWORK=off go run ./cmd/wfctl plugin validate --file /Users/jon/.config/superpowers/worktrees/workflow-plugin-cicd/codex-cicd-pr2-review-fix/plugin.json --strict-contracts passed from the Workflow checkout

@intel352

intel352 commented May 1, 2026

Copy link
Copy Markdown
Contributor

@copilot Add this as part of the PR scope: include or update a GitHub Actions PR check that validates strict Workflow plugin contracts. The check should fail when plugin.json is missing and should run the current Workflow CLI strict validation, for example:

name: wfctl strict contracts
on:
  pull_request:
  push:
    branches: [main, master]

jobs:
  wfctl-strict-contracts:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version-file: go.mod
      - name: Validate strict plugin contracts
        run: go run github.com/GoCodeAlone/workflow/cmd/wfctl@v0.20.1 plugin validate --file plugin.json --strict-contracts

Adjust branch filters and Go setup to match this repository. If the repo uses an existing CI workflow, add this as a job there instead of creating duplicate workflow clutter. Include the check result in the PR validation notes.

@intel352

intel352 commented May 1, 2026

Copy link
Copy Markdown
Contributor

@copilot please try again using Claude Sonnet 4.6.

Continue the original task for this PR. Make sure the PR is not left empty, add or update strict gRPC contract descriptors as applicable, add a PR check that runs wfctl strict validation, run the repository tests, and keep this PR ready for review with Copilot assigned as reviewer.

Copilot AI commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please try again using Claude Sonnet 4.6.

Continue the original task for this PR. Make sure the PR is not left empty, add or update strict gRPC contract descriptors as applicable, add a PR c...

Continuing from where the PR left off. The strict contract descriptors from the previous commits are intact. Added .github/workflows/ci.yml in d590960 with two jobs:

  • test — runs go test ./... on every PR and push to main/master
  • wfctl-strict-contracts — explicitly fails if plugin.json is missing, then runs go run github.com/GoCodeAlone/workflow/cmd/wfctl@v0.20.1 plugin validate --file plugin.json --strict-contracts

Both jobs use go-version-file: go.mod, GOWORK: "off", and the private module URL rewrite matching the existing release.yml pattern. A top-level permissions: contents: read limits GITHUB_TOKEN scope. All local tests pass.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plugin.contracts.json
Comment on lines +999 to +1012
"outputs": [
{
"key": "status",
"type": "string"
},
{
"key": "image",
"type": "string"
},
{
"key": "message",
"type": "string"
}
]
Comment thread internal/plugin_test.go
Comment on lines +379 to +389
var contracts struct {
Version string `json:"version"`
Plugin string `json:"plugin"`
Strict bool `json:"strict"`
Modules []struct {
Type string `json:"type"`
} `json:"modules"`
Steps []struct {
Type string `json:"type"`
} `json:"steps"`
}
Comment thread internal/plugin_test.go Outdated
Comment on lines +221 to +223
result, err := inst.Execute(context.Background(), nil, nil, nil, nil, map[string]any{
"command": "echo hello",
})
Comment thread internal/plugin_test.go Outdated
Comment on lines +448 to +450
sort.Strings(manifest.Capabilities.StepTypes)
sort.Strings(codeTypes)

Comment thread plugin.json
{
"key": "message",
"type": "string",
"description": "Human-readable result message"

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/plugin_test.go
Comment on lines +379 to +425
var contracts struct {
Version string `json:"version"`
Plugin string `json:"plugin"`
Strict bool `json:"strict"`
Modules []struct {
Type string `json:"type"`
} `json:"modules"`
Steps []struct {
Type string `json:"type"`
} `json:"steps"`
}
if err := json.Unmarshal(data, &contracts); err != nil {
t.Fatalf("parse plugin.contracts.json: %v", err)
}

if contracts.Version == "" {
t.Error("contracts.version is empty")
}
if !contracts.Strict {
t.Error("contracts.strict must be true")
}

// Verify modules coverage.
p := internal.NewCICDPlugin()
mp := p.(sdk.ModuleProvider)
moduleSet := make(map[string]bool, len(contracts.Modules))
for _, m := range contracts.Modules {
moduleSet[m.Type] = true
}
for _, modType := range mp.ModuleTypes() {
if !moduleSet[modType] {
t.Errorf("plugin.contracts.json missing module descriptor for %q", modType)
}
}

// Verify steps coverage.
sp := p.(sdk.StepProvider)
stepSet := make(map[string]bool, len(contracts.Steps))
for _, s := range contracts.Steps {
stepSet[s.Type] = true
}
for _, stepType := range sp.StepTypes() {
if !stepSet[stepType] {
t.Errorf("plugin.contracts.json missing step descriptor for %q", stepType)
}
}
}
Comment thread internal/plugin_test.go Outdated
Comment on lines +448 to +450
sort.Strings(manifest.Capabilities.StepTypes)
sort.Strings(codeTypes)

@intel352

intel352 commented May 2, 2026

Copy link
Copy Markdown
Contributor

@copilot please continue this PR using Claude Sonnet 4.6 and address the remaining merge gates.

Current gate state I see:

  • pending checks: 0
  • failing checks: 0
  • unresolved review threads: 8
  • passing wfctl strict check present: true

Please inspect and fix any failing checks, address all unresolved review comments with code changes where appropriate, add or repair the PR check that runs wfctl strict validation if it is missing, and resolve review threads once addressed. Keep the PR ready for review with Copilot requested as reviewer.

… contracts validation, test cleanup

Agent-Logs-Url: https://github.com/GoCodeAlone/workflow-plugin-cicd/sessions/7396e2ba-5940-43be-ac0b-b02213cffee3

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>

Copilot AI commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please continue this PR using Claude Sonnet 4.6 and address the remaining merge gates.

Current gate state I see:...

Addressed all 8 unresolved review threads in 18eeb31:

  • step.container_build outputs (plugin.json + plugin.contracts.json): Added missing service and strategy keys to match what deployStep.Execute() actually emits.
  • TestPluginContractsJSON: Extended to parse and validate the contracts section — now asserts every module/step type has an entry with mode: "strict".
  • Redundant Execute config params: Changed all Execute(...) calls in tests to pass nil instead of a config map, since config is read from the CreateStep instance (the execute parameter was always ignored).
  • Dead sort.Strings() calls: Removed from TestStepTypesConsistency along with the unused sort import.

All tests pass; CI workflow with wfctl --strict-contracts check remains in place.

@intel352 intel352 requested a review from Copilot May 2, 2026 19:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/plugin_test.go Outdated
}

// Every module type returned by ModuleTypes must have a matching schema.
mp := p.(sdk.ModuleProvider)
Comment thread internal/plugin_test.go Outdated
// returns combined output and exit code.
func TestShellExecStep(t *testing.T) {
p := internal.NewCICDPlugin()
sp := p.(sdk.StepProvider)
Comment thread internal/plugin_test.go Outdated
// returns combined output and exit code.
func TestShellExecStep(t *testing.T) {
p := internal.NewCICDPlugin()
sp := p.(sdk.StepProvider)
Comment thread internal/plugin_test.go
Comment on lines +234 to +237
exitCode, ok := result.Output["exit_code"].(int)
if !ok {
t.Fatalf("exit_code type = %T, want int", result.Output["exit_code"])
}
Comment thread internal/plugin_test.go
Comment on lines +286 to +287
// TestDeploySteps verifies that all deploy step types execute without error and
// return the expected output keys.
Comment thread internal/plugin_test.go Outdated
Comment on lines +319 to +321
if _, ok := result.Output["status"]; !ok {
t.Error("output missing 'status' key")
}
Comment thread plugin.json Outdated
Comment on lines +716 to +722
"description": "Git ref (branch, tag, or commit SHA) to check out; either ref or branch is required"
},
{
"key": "branch",
"label": "Branch",
"type": "string",
"description": "Alias for ref; used when ref is absent"
Comment thread internal/plugin.go Outdated
Comment on lines +3 to +6
// Each advertised module and step declares a typed schema contract that is
// exposed via the SchemaProvider interface (gRPC) and as stepSchemas entries
// in plugin.json, so that host-side tooling can validate payloads at
// code-generation, compilation, or startup time rather than at runtime.
Comment thread .github/workflows/ci.yml Outdated
Comment on lines +22 to +23
- name: Configure Go private modules
run: git config --global url."https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
Comment thread .github/workflows/ci.yml Outdated
Comment on lines +42 to +43
- name: Configure Go private modules
run: git config --global url."https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/"
@intel352 intel352 requested a review from Copilot May 2, 2026 22:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@intel352

intel352 commented May 6, 2026

Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

…ypes, deploy outputs, CI scope

Agent-Logs-Url: https://github.com/GoCodeAlone/workflow-plugin-cicd/sessions/48561ecb-b02b-4383-8ef0-f3b879b4e8f9

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>

Copilot AI commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Applied all changes from that review thread in 7cfed68:

  • Unchecked type assertions: All p.(sdk.ModuleProvider) / p.(sdk.StepProvider) unchecked assertions replaced with checked x, ok := ...; if !ok { t.Fatal(...) } guards across every test function.
  • exit_code numeric type: Shell exec tests now accept both int and float64 (protobuf/JSON deserialisation can produce either).
  • TestDeploySteps output keys: Now asserts all 5 declared keys (status, service, image, strategy, message) instead of just status.
  • plugin.go package comment: Clarified that module schemas go via SchemaProvider (gRPC) while step schemas go via stepSchemas in plugin.json.
  • plugin.json git_checkout descriptions: Step description simplified; branch field description changed from "alias" to "alternative to ref".
  • CI URL rewrite scope: Narrowed from all github.com/ to github.com/GoCodeAlone/; switched to github.token instead of secrets.GITHUB_TOKEN.

@intel352 intel352 merged commit 5ee9fb9 into master May 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate workflow-plugin-cicd to strict gRPC proto contracts

3 participants