From bf0cfe7e7f8b9624966220c9cd70d744e9c09d38 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 01:28:14 -0500 Subject: [PATCH 01/42] fix: align action inputs with pipeline flags --- README.md | 2 +- action.yml | 93 ++++++++++++++++++++++++++++- cmd/secretsync/cmd/pipeline.go | 18 ++++-- cmd/secretsync/cmd/pipeline_test.go | 28 +++++++++ docs/ACTION_QUICK_REFERENCE.md | 6 +- docs/GETTING_STARTED.md | 4 +- docs/GITHUB_ACTIONS.md | 6 +- 7 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 cmd/secretsync/cmd/pipeline_test.go diff --git a/README.md b/README.md index 890b449..3402643 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ crewai_tools = get_tools("crewai") secretsync validate --config pipeline.yaml # Dry run with enhanced diff output (v1.2.0) -secretsync pipeline --config pipeline.yaml --dry-run --format side-by-side +secretsync pipeline --config pipeline.yaml --dry-run --output side-by-side # Full pipeline execution with metrics (v1.1.0) secretsync pipeline --config pipeline.yaml --metrics-port 9090 diff --git a/action.yml b/action.yml index 2211101..01c76fd 100644 --- a/action.yml +++ b/action.yml @@ -2,6 +2,67 @@ name: "SecretSync" author: "jbcom" description: "Sync secrets from HashiCorp Vault to AWS Secrets Manager across multiple accounts" +inputs: + config: + description: "Path to SecretSync configuration file" + required: false + default: "config.yaml" + targets: + description: "Comma-separated list of targets to process" + required: false + default: "" + dry-run: + description: "Run without making changes" + required: false + default: "false" + merge-only: + description: "Only run the merge phase" + required: false + default: "false" + sync-only: + description: "Only run the sync phase" + required: false + default: "false" + discover: + description: "Enable dynamic target discovery from AWS Organizations/Identity Center" + required: false + default: "false" + output-format: + description: "Output format: human, json, github, compact, side-by-side" + required: false + default: "github" + compute-diff: + description: "Compute and show diff even when not in dry-run mode" + required: false + default: "false" + exit-code: + description: "Use exit codes: 0=no changes, 1=changes, 2=errors" + required: false + default: "false" + continue-on-error: + description: "Continue processing remaining targets after an error" + required: false + default: "true" + parallelism: + description: "Maximum concurrent target operations; 0 uses config/default" + required: false + default: "0" + metrics-addr: + description: "Metrics server bind address" + required: false + default: "0.0.0.0" + metrics-port: + description: "Metrics server port; 0 disables metrics" + required: false + default: "0" + log-level: + description: "Logging level: debug, info, warn, error" + required: false + default: "info" + log-format: + description: "Log format: text or json" + required: false + default: "text" runs: using: "docker" # Prefer a digest-pinned image once the release workflow can refresh the @@ -11,12 +72,38 @@ runs: # 3. image: "docker://jbcom/secretssync:v1@sha256:" # Until then, keep the release-please-managed tag reference below. image: "docker://jbcom/secretssync:v1" # x-release-please-version + args: + - "pipeline" + - "--config" + - "${{ inputs.config }}" + - "--targets" + - "${{ inputs.targets }}" + - "--dry-run=${{ inputs.dry-run }}" + - "--merge-only=${{ inputs.merge-only }}" + - "--sync-only=${{ inputs.sync-only }}" + - "--discover=${{ inputs.discover }}" + - "--output" + - "${{ inputs.output-format }}" + - "--diff=${{ inputs.compute-diff }}" + - "--exit-code=${{ inputs.exit-code }}" + - "--continue-on-error=${{ inputs.continue-on-error }}" + - "--parallelism" + - "${{ inputs.parallelism }}" + - "--metrics-addr" + - "${{ inputs.metrics-addr }}" + - "--metrics-port" + - "${{ inputs.metrics-port }}" + - "--log-level" + - "${{ inputs.log-level }}" + - "--log-format" + - "${{ inputs.log-format }}" branding: icon: "lock" color: "blue" -# Configuration via environment variables (GitHub Actions inputs map to env vars) -# See https://github.com/jbcom/secrets-sync#configuration for full documentation +# Action inputs are passed to the Docker action as explicit CLI flags. +# The CLI also supports SECRETSYNC_* environment variables for direct container +# use; see https://github.com/jbcom/secrets-sync#configuration for full docs. # # Required: # SECRETSYNC_CONFIG - Path to config file (default: config.yaml) @@ -27,7 +114,7 @@ branding: # SECRETSYNC_MERGE_ONLY - Only run merge phase (default: false) # SECRETSYNC_SYNC_ONLY - Only run sync phase (default: false) # SECRETSYNC_DISCOVER - Enable dynamic target discovery (default: false) -# SECRETSYNC_OUTPUT - Output format: human, json, github (default: github) +# SECRETSYNC_OUTPUT - Output format: human, json, github, compact, side-by-side (default: github) # SECRETSYNC_DIFF - Show diff even without dry-run (default: false) # SECRETSYNC_EXIT_CODE - Use exit codes for CI (default: false) # SECRETSYNC_LOG_LEVEL - Log level: debug, info, warn, error (default: info) diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index cbd61ae..857dd1f 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -24,6 +24,8 @@ var ( outputFormat string computeDiff bool exitCodeMode bool + continueOnError bool + parallelism int ) // pipelineCmd runs the full merge-then-sync pipeline @@ -39,11 +41,11 @@ var pipelineCmd = &cobra.Command{ 2. SYNC PHASE: Sync merged secrets to target AWS accounts - Assumes Control Tower execution role in each account - - Runs in parallel (respects --parallel setting) + - Runs in parallel (respects --parallelism or config settings) 3. DIFF REPORTING: Track and report all changes - Zero-sum validation for migration verification - - Multiple output formats (human, JSON, GitHub Actions) + - Multiple output formats (human, JSON, GitHub Actions, compact, side-by-side) - CI/CD-friendly exit codes (0=no changes, 1=changes, 2=errors) Examples: @@ -60,6 +62,9 @@ Examples: # GitHub Actions compatible output secretsync pipeline --config config.yaml --dry-run --output github + # Visual side-by-side diff output + secretsync pipeline --config config.yaml --dry-run --output side-by-side + # Specific targets only secretsync pipeline --config config.yaml --targets "Serverless_Stg,Serverless_Prod" @@ -79,9 +84,11 @@ func init() { pipelineCmd.Flags().BoolVar(&syncOnly, "sync-only", false, "only run sync phase") pipelineCmd.Flags().BoolVar(&dryRun, "dry-run", false, "dry run mode (no changes)") pipelineCmd.Flags().BoolVar(&discoverTargets, "discover", false, "enable dynamic target discovery from AWS Organizations/Identity Center") + pipelineCmd.Flags().BoolVar(&continueOnError, "continue-on-error", true, "continue processing remaining targets after an error") + pipelineCmd.Flags().IntVar(¶llelism, "parallelism", 0, "max concurrent target operations (default: pipeline.merge.parallel config or 4)") // Diff and output options - pipelineCmd.Flags().StringVarP(&outputFormat, "output", "o", "human", "output format: human, json, github, compact") + pipelineCmd.Flags().StringVarP(&outputFormat, "output", "o", "human", "output format: human, json, github, compact, side-by-side") pipelineCmd.Flags().BoolVar(&computeDiff, "diff", false, "compute and show diff even when not in dry-run mode") pipelineCmd.Flags().BoolVar(&exitCodeMode, "exit-code", false, "use exit codes: 0=no changes, 1=changes, 2=errors (useful for CI/CD)") } @@ -144,7 +151,8 @@ func runPipeline(cmd *cobra.Command, args []string) error { Operation: op, Targets: targetList, DryRun: dryRun, - ContinueOnError: true, + ContinueOnError: continueOnError, + Parallelism: parallelism, OutputFormat: format, ComputeDiff: computeDiff || dryRun, } @@ -204,6 +212,8 @@ func parseOutputFormat(s string) diff.OutputFormat { return diff.OutputFormatGitHub case "compact": return diff.OutputFormatCompact + case "side-by-side", "sidebyside", "side_by_side": + return diff.OutputFormatSideBySide default: return diff.OutputFormatHuman } diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go new file mode 100644 index 0000000..c7cd24b --- /dev/null +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "testing" + + "github.com/jbcom/secrets-sync/pkg/diff" +) + +func TestParseOutputFormat(t *testing.T) { + tests := map[string]diff.OutputFormat{ + "human": diff.OutputFormatHuman, + "json": diff.OutputFormatJSON, + "github": diff.OutputFormatGitHub, + "compact": diff.OutputFormatCompact, + "side-by-side": diff.OutputFormatSideBySide, + "sidebyside": diff.OutputFormatSideBySide, + "side_by_side": diff.OutputFormatSideBySide, + "unknown": diff.OutputFormatHuman, + } + + for input, expected := range tests { + t.Run(input, func(t *testing.T) { + if actual := parseOutputFormat(input); actual != expected { + t.Fatalf("parseOutputFormat(%q) = %q, want %q", input, actual, expected) + } + }) + } +} diff --git a/docs/ACTION_QUICK_REFERENCE.md b/docs/ACTION_QUICK_REFERENCE.md index 1c1ca20..b255f35 100644 --- a/docs/ACTION_QUICK_REFERENCE.md +++ b/docs/ACTION_QUICK_REFERENCE.md @@ -28,9 +28,13 @@ | `merge-only` | `false` | Only run merge phase | | `sync-only` | `false` | Only run sync phase | | `discover` | `false` | Enable dynamic discovery | -| `output-format` | `github` | Output format (human, json, github, compact) | +| `output-format` | `github` | Output format (human, json, github, compact, side-by-side) | | `compute-diff` | `false` | Show diff even without dry-run | | `exit-code` | `false` | Use exit codes (0=no changes, 1=changes, 2=errors) | +| `continue-on-error` | `true` | Continue processing remaining targets after an error | +| `parallelism` | `0` | Maximum concurrent target operations (`0` uses config/default) | +| `metrics-addr` | `0.0.0.0` | Metrics server bind address | +| `metrics-port` | `0` | Metrics server port (`0` disables metrics) | | `log-level` | `info` | Log level (debug, info, warn, error) | | `log-format` | `text` | Log format (text, json) | diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 7f6864c..47cdd54 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -165,10 +165,10 @@ curl http://localhost:9090/health ```bash # Side-by-side comparison -secretsync pipeline --config config.yaml --dry-run --format side-by-side +secretsync pipeline --config config.yaml --dry-run --output side-by-side # JSON output for automation -secretsync pipeline --config config.yaml --dry-run --format json +secretsync pipeline --config config.yaml --dry-run --output json ``` #### 3. Secret Versioning (v1.2.0) diff --git a/docs/GITHUB_ACTIONS.md b/docs/GITHUB_ACTIONS.md index 2a14fee..a3e1be6 100644 --- a/docs/GITHUB_ACTIONS.md +++ b/docs/GITHUB_ACTIONS.md @@ -47,9 +47,13 @@ All inputs correspond to CLI flags and are optional: | `merge-only` | Only run merge phase | `false` | `--merge-only` | | `sync-only` | Only run sync phase | `false` | `--sync-only` | | `discover` | Enable dynamic target discovery | `false` | `--discover` | -| `output-format` | Output format (human, json, github, compact) | `github` | `--output` | +| `output-format` | Output format (human, json, github, compact, side-by-side) | `github` | `--output` | | `compute-diff` | Show diff even without dry-run | `false` | `--diff` | | `exit-code` | Use exit codes for CI/CD | `false` | `--exit-code` | +| `continue-on-error` | Continue processing remaining targets after an error | `true` | `--continue-on-error` | +| `parallelism` | Maximum concurrent target operations (`0` uses config/default) | `0` | `--parallelism` | +| `metrics-addr` | Metrics server bind address | `0.0.0.0` | `--metrics-addr` | +| `metrics-port` | Metrics server port (`0` disables metrics) | `0` | `--metrics-port` | | `log-level` | Logging level (debug, info, warn, error) | `info` | `--log-level` | | `log-format` | Log format (text, json) | `text` | `--log-format` | From 310fe27016fa84d002632ad9e42617b8da21d1aa Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 01:43:03 -0500 Subject: [PATCH 02/42] fix: preserve pipeline errors in exit-code mode --- cmd/secretsync/cmd/pipeline.go | 24 +++++++++++++++++--- cmd/secretsync/cmd/pipeline_test.go | 34 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index 857dd1f..b669105 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -180,9 +180,15 @@ func runPipeline(cmd *cobra.Command, args []string) error { } // Determine exit behavior + hasErrors := pipelineHadErrors(err, results) if exitCodeMode { + if hasErrors { + cancel() + os.Exit(2) + } exitCode := p.ExitCode() if exitCode != 0 { + cancel() os.Exit(exitCode) } return nil @@ -193,14 +199,26 @@ func runPipeline(cmd *cobra.Command, args []string) error { } // Check for any failures + if hasErrors { + return fmt.Errorf("pipeline completed with errors") + } + + l.Info("Pipeline completed successfully") + return nil +} + +func pipelineHadErrors(err error, results []pipeline.Result) bool { + if err != nil { + return true + } + for _, r := range results { if !r.Success { - return fmt.Errorf("pipeline completed with errors") + return true } } - l.Info("Pipeline completed successfully") - return nil + return false } // parseOutputFormat converts string to OutputFormat diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go index c7cd24b..0f7e826 100644 --- a/cmd/secretsync/cmd/pipeline_test.go +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -1,9 +1,11 @@ package cmd import ( + "errors" "testing" "github.com/jbcom/secrets-sync/pkg/diff" + "github.com/jbcom/secrets-sync/pkg/pipeline" ) func TestParseOutputFormat(t *testing.T) { @@ -26,3 +28,35 @@ func TestParseOutputFormat(t *testing.T) { }) } } + +func TestPipelineHadErrors(t *testing.T) { + tests := map[string]struct { + err error + results []pipeline.Result + want bool + }{ + "run error": { + err: errors.New("connection failed"), + want: true, + }, + "target failure": { + results: []pipeline.Result{{Target: "prod", Success: false}}, + want: true, + }, + "all targets successful": { + results: []pipeline.Result{{Target: "prod", Success: true}}, + want: false, + }, + "no results": { + want: false, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + if got := pipelineHadErrors(tc.err, tc.results); got != tc.want { + t.Fatalf("pipelineHadErrors() = %v, want %v", got, tc.want) + } + }) + } +} From 947737702130aed625799be6a012291b24ea11f8 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 01:45:14 -0500 Subject: [PATCH 03/42] fix: align continue-on-error defaults --- pkg/pipeline/pipeline.go | 2 +- pkg/pipeline/pipeline_test.go | 10 ++++++++++ python/secretssync/secretssync.go | 2 +- python/secretssync/secretssync_test.go | 23 +++++++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 python/secretssync/secretssync_test.go diff --git a/pkg/pipeline/pipeline.go b/pkg/pipeline/pipeline.go index 4189e5f..4bdec93 100644 --- a/pkg/pipeline/pipeline.go +++ b/pkg/pipeline/pipeline.go @@ -89,7 +89,7 @@ func DefaultOptions() Options { return Options{ Operation: OperationPipeline, DryRun: false, - ContinueOnError: false, + ContinueOnError: true, Parallelism: 4, ComputeDiff: false, } diff --git a/pkg/pipeline/pipeline_test.go b/pkg/pipeline/pipeline_test.go index 285396c..a4279f4 100644 --- a/pkg/pipeline/pipeline_test.go +++ b/pkg/pipeline/pipeline_test.go @@ -90,6 +90,16 @@ func TestNew(t *testing.T) { } } +func TestDefaultOptions(t *testing.T) { + opts := DefaultOptions() + + assert.Equal(t, OperationPipeline, opts.Operation) + assert.False(t, opts.DryRun) + assert.True(t, opts.ContinueOnError) + assert.Equal(t, 4, opts.Parallelism) + assert.False(t, opts.ComputeDiff) +} + func TestPipeline_Operations(t *testing.T) { tests := []struct { name string diff --git a/python/secretssync/secretssync.go b/python/secretssync/secretssync.go index bcab42c..583e417 100644 --- a/python/secretssync/secretssync.go +++ b/python/secretssync/secretssync.go @@ -73,7 +73,7 @@ func DefaultSyncOptions() *SyncOptions { DryRun: false, Operation: OperationPipeline, Targets: "", - ContinueOnError: false, + ContinueOnError: true, Parallelism: 4, ComputeDiff: false, OutputFormat: OutputFormatHuman, diff --git a/python/secretssync/secretssync_test.go b/python/secretssync/secretssync_test.go new file mode 100644 index 0000000..79afbab --- /dev/null +++ b/python/secretssync/secretssync_test.go @@ -0,0 +1,23 @@ +package secretssync + +import "testing" + +func TestDefaultSyncOptions(t *testing.T) { + opts := DefaultSyncOptions() + + if opts.Operation != OperationPipeline { + t.Fatalf("Operation = %q, want %q", opts.Operation, OperationPipeline) + } + if opts.DryRun { + t.Fatal("DryRun = true, want false") + } + if !opts.ContinueOnError { + t.Fatal("ContinueOnError = false, want true") + } + if opts.Parallelism != 4 { + t.Fatalf("Parallelism = %d, want 4", opts.Parallelism) + } + if opts.OutputFormat != OutputFormatHuman { + t.Fatalf("OutputFormat = %q, want %q", opts.OutputFormat, OutputFormatHuman) + } +} From ce2dc1ca3eff46223dc407cc8513c0d759572bc4 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 02:18:27 -0500 Subject: [PATCH 04/42] docs: align secrets-sync standalone release docs --- .goreleaser.yml | 17 ++++++----------- Makefile | 4 ++-- README.md | 8 ++++---- docs/PYTHON_BINDINGS.md | 2 +- docs/getting-started/installation.md | 4 ++-- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 453b941..c5a7701 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -98,23 +98,18 @@ release: ### Installation - **Docker:** - ```bash - docker pull jbcom/secretssync:{{ .Version }} - ``` + **Binary:** + Download from the assets below for your platform. - **Helm (OCI):** + **Go install:** ```bash - helm install secretsync oci://registry-1.docker.io/jbcom/secretssync --version {{ .Version }} + go install github.com/jbcom/secrets-sync/cmd/secretsync@{{ .Tag }} ``` - **Binary:** - Download from the assets below for your platform. - footer: | --- **Full Changelog**: https://github.com/jbcom/secrets-sync/compare/{{ .PreviousTag }}...{{ .Tag }} -# Docker images and Helm charts are built/pushed separately -# via dedicated workflow jobs for better control +# Container and chart artifacts are outside this binary release workflow. +# Keep release notes limited to artifacts built here. dockers: [] diff --git a/Makefile b/Makefile index 293e99c..97b6f0f 100644 --- a/Makefile +++ b/Makefile @@ -40,8 +40,8 @@ python-bindings: @mkdir -p $(PYTHON_OUTPUT) $(GOPY) pkg -output=$(PYTHON_OUTPUT) -vm=$(PYTHON) -name=$(PYTHON_PKG) \ -version=$(VERSION) \ - -author="Extended Data Library" \ - -email="support@extended-data.dev" \ + -author="jbcom" \ + -email="jon@jonbogaty.com" \ -url="https://github.com/jbcom/secrets-sync" \ -desc="Enterprise-grade secret synchronization pipeline with Python bindings" \ ./python/secretssync diff --git a/README.md b/README.md index 3402643..a25a779 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ SecretSync provides **fully automated, enterprise-grade secret synchronization** across multiple cloud providers and secret stores. Built for scale with a **two-phase pipeline architecture** (merge → sync), it supports inheritance, dynamic target discovery, and CI/CD-friendly diff reporting. -## 🏢 Part of Extended Data Library +## 🏢 Independent Repository, Extended Data Integration -SecretSync is part of the [Extended Data Library](https://github.com/jbcom/secrets-sync) ecosystem - a collection of high-performance, enterprise-grade tools for data management, secret handling, and infrastructure automation. +SecretSync is an independent [jbcom/secrets-sync](https://github.com/jbcom/secrets-sync) repository and MIT-licensed release artifact for secret synchronization workflows. -**🐍 Python Integration**: SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with the [extended-data](https://github.com/jbcom/extended-data) library and Python-based AI agents. +**🐍 Python Integration**: SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with the [extended-data](https://github.com/jbcom/extended-data) Python package and Python-based AI agents. **🚀 Perfect for:** Multi-account AWS environments, Kubernetes deployments, CI/CD pipelines, and enterprise secret management at scale. @@ -381,7 +381,7 @@ helm install secretsync secretsync/secretsync \ ```bash # Run with config file docker run -v $(pwd)/config.yaml:/config.yaml \ - jbcom/secrets-sync-secretssync pipeline --config /config.yaml + jbcom/secretssync:v1 pipeline --config /config.yaml # Multi-arch images available: linux/amd64, linux/arm64 ``` diff --git a/docs/PYTHON_BINDINGS.md b/docs/PYTHON_BINDINGS.md index a0ed1a4..89d19d7 100644 --- a/docs/PYTHON_BINDINGS.md +++ b/docs/PYTHON_BINDINGS.md @@ -1,6 +1,6 @@ # Python Bindings -SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with Python applications, AI agents, and the Extended Data Library packages. +SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with Python applications, AI agents, and the `extended-data` Python package. ## Overview diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 4e13e10..0b70f09 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -8,7 +8,7 @@ ## Install the CLI ```bash -# Install the latest CLI from the monorepo module path +# Install the latest CLI from the standalone module path go install github.com/jbcom/secrets-sync/cmd/secretsync@latest ``` @@ -34,7 +34,7 @@ make build ## GitHub Action -Use the packaged action from the monorepo subdirectory and pin to a package tag: +Use the packaged action from this standalone repository and pin to a release tag: ```yaml - uses: jbcom/secrets-sync@secretssync-v2.0.2 From d1636d8e419614d02a88a4e218a9f3de5b8c1bbe Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 02:55:34 -0500 Subject: [PATCH 05/42] fix: emit stable pipeline json envelope --- cmd/secretsync/cmd/pipeline.go | 122 ++++++++++++++++++++++++- cmd/secretsync/cmd/pipeline_test.go | 105 +++++++++++++++++++++ docs/ACTION_QUICK_REFERENCE.md | 3 +- docs/GETTING_STARTED.md | 4 + docs/PYTHON_BINDINGS.md | 4 + docs/TWO_PHASE_ARCHITECTURE.md | 31 +++++-- python/secretssync/secretssync.go | 12 ++- python/secretssync/secretssync_test.go | 19 +++- 8 files changed, 284 insertions(+), 16 deletions(-) diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index b669105..85f9925 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -2,12 +2,14 @@ package cmd import ( "context" + "encoding/json" "fmt" "os" "os/signal" "sort" "strings" "syscall" + "time" "github.com/jbcom/secrets-sync/pkg/diff" "github.com/jbcom/secrets-sync/pkg/pipeline" @@ -52,7 +54,7 @@ Examples: # Full pipeline secretsync pipeline --config config.yaml - # Dry run with diff output (validates zero-sum) + # Dry run with machine-readable result and nested diff output secretsync pipeline --config config.yaml --dry-run --output json # CI/CD mode with exit codes @@ -166,11 +168,21 @@ func runPipeline(cmd *cobra.Command, args []string) error { }).Info("Starting pipeline") // Run pipeline + start := time.Now() results, err := p.Run(ctx, opts) + duration := time.Since(start) - // Print diff output if computed - if d := p.Diff(); d != nil { - diffOutput := p.FormatDiff(format) + // Print machine JSON as a stable result envelope for both diff and non-diff runs. + pipelineDiff := p.Diff() + diffOutput := "" + if pipelineDiff != nil { + diffOutput = p.FormatDiff(format) + } + if format == diff.OutputFormatJSON { + if jsonErr := printPipelineJSONSummary(results, err, duration, diffOutput, pipelineDiff); jsonErr != nil { + return jsonErr + } + } else if pipelineDiff != nil { if diffOutput != "" { fmt.Println(diffOutput) } @@ -294,3 +306,105 @@ func printResults(results []pipeline.Result) { fmt.Printf("\nTotal: %d/%d succeeded\n", successCount, len(results)) fmt.Println(strings.Repeat("=", 60)) } + +type pipelineJSONSummary struct { + Success bool `json:"success"` + TargetCount int `json:"target_count"` + SecretsProcessed int `json:"secrets_processed"` + SecretsAdded int `json:"secrets_added"` + SecretsModified int `json:"secrets_modified"` + SecretsRemoved int `json:"secrets_removed"` + SecretsUnchanged int `json:"secrets_unchanged"` + DurationMs int64 `json:"duration_ms"` + ErrorMessage string `json:"error_message,omitempty"` + Results []pipelineJSONItem `json:"results"` + DiffOutput string `json:"diff_output,omitempty"` + Diff *diff.PipelineDiff `json:"diff,omitempty"` +} + +type pipelineJSONItem struct { + Target string `json:"target"` + Phase string `json:"phase"` + Operation string `json:"operation"` + Success bool `json:"success"` + Error string `json:"error,omitempty"` + DurationMs int64 `json:"duration_ms"` + Details pipeline.ResultDetails `json:"details,omitempty"` + Diff *diff.TargetDiff `json:"diff,omitempty"` +} + +func printPipelineJSONSummary( + results []pipeline.Result, + runErr error, + duration time.Duration, + diffOutput string, + pipelineDiff *diff.PipelineDiff, +) error { + payload := newPipelineJSONSummary(results, runErr, duration, diffOutput, pipelineDiff) + encoded, err := json.MarshalIndent(payload, "", " ") + if err != nil { + return fmt.Errorf("failed to encode pipeline JSON output: %w", err) + } + fmt.Println(string(encoded)) + return nil +} + +func newPipelineJSONSummary( + results []pipeline.Result, + runErr error, + duration time.Duration, + diffOutput string, + pipelineDiff *diff.PipelineDiff, +) pipelineJSONSummary { + summary := pipelineJSONSummary{ + Success: runErr == nil, + DurationMs: duration.Milliseconds(), + Results: make([]pipelineJSONItem, 0, len(results)), + DiffOutput: diffOutput, + Diff: pipelineDiff, + } + if runErr != nil { + summary.ErrorMessage = runErr.Error() + } + + targetsSeen := make(map[string]struct{}) + for _, result := range results { + if result.Target != "" { + targetsSeen[result.Target] = struct{}{} + } + + summary.SecretsProcessed += result.Details.SecretsProcessed + summary.SecretsAdded += result.Details.SecretsAdded + summary.SecretsModified += result.Details.SecretsModified + summary.SecretsRemoved += result.Details.SecretsRemoved + summary.SecretsUnchanged += result.Details.SecretsUnchanged + + item := pipelineJSONItem{ + Target: result.Target, + Phase: result.Phase, + Operation: result.Operation, + Success: result.Success, + DurationMs: result.Duration.Milliseconds(), + Details: result.Details, + Diff: result.Diff, + } + if result.Error != nil { + item.Error = result.Error.Error() + } + summary.Results = append(summary.Results, item) + + if !result.Success { + summary.Success = false + if summary.ErrorMessage == "" { + if item.Error != "" { + summary.ErrorMessage = item.Error + } else { + summary.ErrorMessage = "pipeline completed with errors" + } + } + } + } + + summary.TargetCount = len(targetsSeen) + return summary +} diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go index 0f7e826..993e931 100644 --- a/cmd/secretsync/cmd/pipeline_test.go +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -1,8 +1,11 @@ package cmd import ( + "encoding/json" "errors" + "strings" "testing" + "time" "github.com/jbcom/secrets-sync/pkg/diff" "github.com/jbcom/secrets-sync/pkg/pipeline" @@ -29,6 +32,108 @@ func TestParseOutputFormat(t *testing.T) { } } +func TestNewPipelineJSONSummaryAggregatesResults(t *testing.T) { + results := []pipeline.Result{ + { + Target: "prod", + Phase: "merge", + Operation: "merge", + Success: true, + Duration: 1500 * time.Millisecond, + Details: pipeline.ResultDetails{ + SecretsProcessed: 2, + SecretsAdded: 1, + SecretsUnchanged: 1, + }, + }, + { + Target: "prod", + Phase: "sync", + Operation: "sync", + Success: true, + Duration: 2500 * time.Millisecond, + Details: pipeline.ResultDetails{ + SecretsProcessed: 2, + SecretsModified: 1, + SecretsRemoved: 1, + }, + }, + { + Target: "staging", + Phase: "sync", + Operation: "sync", + Success: true, + Duration: time.Second, + Details: pipeline.ResultDetails{ + SecretsProcessed: 1, + SecretsUnchanged: 1, + }, + }, + } + pipelineDiff := &diff.PipelineDiff{ + Summary: diff.ChangeSummary{Added: 1, Modified: 1, Total: 2}, + DryRun: true, + } + + summary := newPipelineJSONSummary(results, nil, 4200*time.Millisecond, `{"summary":{"added":1}}`, pipelineDiff) + + if !summary.Success { + t.Fatal("Success = false, want true") + } + if summary.TargetCount != 2 { + t.Fatalf("TargetCount = %d, want 2", summary.TargetCount) + } + if summary.SecretsProcessed != 5 { + t.Fatalf("SecretsProcessed = %d, want 5", summary.SecretsProcessed) + } + if summary.SecretsAdded != 1 || summary.SecretsModified != 1 || summary.SecretsRemoved != 1 || summary.SecretsUnchanged != 2 { + t.Fatalf("unexpected secret counts: %+v", summary) + } + if summary.DurationMs != 4200 { + t.Fatalf("DurationMs = %d, want 4200", summary.DurationMs) + } + if len(summary.Results) != len(results) { + t.Fatalf("len(Results) = %d, want %d", len(summary.Results), len(results)) + } + if summary.Results[0].DurationMs != 1500 { + t.Fatalf("Results[0].DurationMs = %d, want 1500", summary.Results[0].DurationMs) + } + if summary.Diff == nil { + t.Fatal("Diff = nil, want structured diff") + } + + encoded, err := json.Marshal(summary) + if err != nil { + t.Fatalf("json.Marshal(summary) failed: %v", err) + } + if !strings.Contains(string(encoded), `"target_count":2`) { + t.Fatalf("encoded summary missing target_count: %s", encoded) + } +} + +func TestNewPipelineJSONSummaryReportsFailures(t *testing.T) { + results := []pipeline.Result{ + { + Target: "prod", + Phase: "sync", + Success: false, + Error: errors.New("assume role failed"), + }, + } + + summary := newPipelineJSONSummary(results, nil, time.Second, "", nil) + + if summary.Success { + t.Fatal("Success = true, want false") + } + if summary.ErrorMessage != "assume role failed" { + t.Fatalf("ErrorMessage = %q, want %q", summary.ErrorMessage, "assume role failed") + } + if summary.Results[0].Error != "assume role failed" { + t.Fatalf("Results[0].Error = %q, want %q", summary.Results[0].Error, "assume role failed") + } +} + func TestPipelineHadErrors(t *testing.T) { tests := map[string]struct { err error diff --git a/docs/ACTION_QUICK_REFERENCE.md b/docs/ACTION_QUICK_REFERENCE.md index b255f35..114440e 100644 --- a/docs/ACTION_QUICK_REFERENCE.md +++ b/docs/ACTION_QUICK_REFERENCE.md @@ -197,7 +197,8 @@ Shows GitHub Actions annotations in workflow logs. ### `json` -Machine-readable JSON output. +Machine-readable pipeline result envelope. Diff details are nested under +`diff` and `diff_output` when diff computation is enabled. ### `compact` diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 47cdd54..b8d2745 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -171,6 +171,10 @@ secretsync pipeline --config config.yaml --dry-run --output side-by-side secretsync pipeline --config config.yaml --dry-run --output json ``` +JSON output is a stable pipeline result envelope with success status, aggregate +secret counts, per-phase `results`, and nested `diff`/`diff_output` fields when +diff computation is enabled. + #### 3. Secret Versioning (v1.2.0) Add to your config: diff --git a/docs/PYTHON_BINDINGS.md b/docs/PYTHON_BINDINGS.md index 89d19d7..a4eda20 100644 --- a/docs/PYTHON_BINDINGS.md +++ b/docs/PYTHON_BINDINGS.md @@ -56,6 +56,10 @@ go install github.com/jbcom/secrets-sync/cmd/secretsync@latest pip install extended-data[secrets] ``` +CLI fallback mode relies on `secretsync pipeline --output json`, which emits +the same stable result envelope for dry-run and apply runs. Diff data is nested +under `diff` and `diff_output` when diff computation is enabled. + ## Usage ### Basic Usage diff --git a/docs/TWO_PHASE_ARCHITECTURE.md b/docs/TWO_PHASE_ARCHITECTURE.md index c7ad03b..91f28a7 100644 --- a/docs/TWO_PHASE_ARCHITECTURE.md +++ b/docs/TWO_PHASE_ARCHITECTURE.md @@ -213,19 +213,32 @@ secretsync pipeline --config config.yaml --merge-only Both phases support diff computation: ```bash -# Dry-run with diff output +# Dry-run with machine-readable result and nested diff output secretsync pipeline --config config.yaml --dry-run --output json # Output: { - "dry_run": true, - "summary": { - "added": 5, - "modified": 2, - "removed": 0, - "unchanged": 43 - }, - "targets": [...] + "success": true, + "target_count": 2, + "secrets_processed": 50, + "secrets_added": 5, + "secrets_modified": 2, + "secrets_removed": 0, + "secrets_unchanged": 43, + "duration_ms": 1284, + "results": [...], + "diff_output": "{...}", + "diff": { + "dry_run": true, + "summary": { + "added": 5, + "modified": 2, + "removed": 0, + "unchanged": 43, + "total": 50 + }, + "targets": [...] + } } ``` diff --git a/python/secretssync/secretssync.go b/python/secretssync/secretssync.go index 583e417..5da4b06 100644 --- a/python/secretssync/secretssync.go +++ b/python/secretssync/secretssync.go @@ -194,7 +194,7 @@ func RunPipeline(configPath string, opts *SyncOptions) *SyncResult { } // Process results - result.TargetCount = len(results) + result.TargetCount = countUniqueTargets(results) result.Success = err == nil for _, r := range results { @@ -303,6 +303,16 @@ func splitTargets(targets string) []string { return result } +func countUniqueTargets(results []pipeline.Result) int { + targets := make(map[string]struct{}) + for _, result := range results { + if result.Target != "" { + targets[result.Target] = struct{}{} + } + } + return len(targets) +} + // ConfigInfo returns information about a configuration file type ConfigInfo struct { Valid bool // Whether the configuration is valid diff --git a/python/secretssync/secretssync_test.go b/python/secretssync/secretssync_test.go index 79afbab..3b5b758 100644 --- a/python/secretssync/secretssync_test.go +++ b/python/secretssync/secretssync_test.go @@ -1,6 +1,10 @@ package secretssync -import "testing" +import ( + "testing" + + "github.com/jbcom/secrets-sync/pkg/pipeline" +) func TestDefaultSyncOptions(t *testing.T) { opts := DefaultSyncOptions() @@ -21,3 +25,16 @@ func TestDefaultSyncOptions(t *testing.T) { t.Fatalf("OutputFormat = %q, want %q", opts.OutputFormat, OutputFormatHuman) } } + +func TestCountUniqueTargets(t *testing.T) { + results := []pipeline.Result{ + {Target: "prod", Phase: "merge"}, + {Target: "prod", Phase: "sync"}, + {Target: "staging", Phase: "sync"}, + {Phase: "sync"}, + } + + if got := countUniqueTargets(results); got != 2 { + t.Fatalf("countUniqueTargets() = %d, want 2", got) + } +} From 50e4f114b9b4b7f3cb03a12c6df399a190665961 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 04:17:37 -0500 Subject: [PATCH 06/42] docs: align secrets-sync release guidance --- README.md | 7 +- action.yml | 2 +- docs/ACTION_QUICK_REFERENCE.md | 30 +- docs/ARCHITECTURE_GAP_ANALYSIS.md | 622 +++------------------------ docs/FAQ.md | 2 +- docs/GETTING_STARTED.md | 6 +- docs/GITHUB_ACTIONS.md | 68 +-- docs/MARKETPLACE.md | 434 ++++++------------- docs/PIPELINE.md | 6 +- docs/PUBLISHING_CHECKLIST.md | 360 ++++------------ docs/SUPPORT.md | 13 +- docs/getting-started/installation.md | 5 +- examples/github-action-workflow.yml | 16 +- 13 files changed, 339 insertions(+), 1232 deletions(-) diff --git a/README.md b/README.md index a25a779..c7e5585 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/jbcom/secrets-sync)](https://goreportcard.com/report/github.com/jbcom/secrets-sync) [![Python Bindings](https://img.shields.io/badge/python-bindings-blue.svg)](./python/) -[Quick Start](#quick-start) • [Package Docs](https://extended-data.dev/packages/secretssync/) • [Repo Docs](./docs/) • [Python Bindings](#python-bindings) • [Examples](./examples/) • [GitHub Action](./docs/GITHUB_ACTIONS.md) +[Quick Start](#quick-start) • [Repo Docs](./docs/) • [Python Bindings](#python-bindings) • [Examples](./examples/) • [GitHub Action](./docs/GITHUB_ACTIONS.md) @@ -288,7 +288,7 @@ SecretSync is available as a GitHub Action for seamless CI/CD integration: ```yaml - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'false' @@ -342,7 +342,6 @@ See [GitHub Actions documentation](./docs/GITHUB_ACTIONS.md) for complete usage ## 📚 Documentation ### Getting Started -- [🌐 Published Package Docs](https://extended-data.dev/packages/secretssync/) - Public package overview, installation paths, and Python integration guidance - [🚀 Getting Started Guide](./docs/GETTING_STARTED.md) - Step-by-step setup tutorial - [❓ FAQ](./docs/FAQ.md) - Frequently asked questions - [📋 Examples](./examples/) - Complete configuration examples @@ -505,7 +504,7 @@ For detailed documentation, see [tests/integration/README.md](./tests/integratio ## 🌟 Community & Support ### Getting Help -- **📚 Documentation**: Start with the [published package docs](https://extended-data.dev/packages/secretssync/) and the repo-local [docs folder](./docs/) +- **📚 Documentation**: Start with the repo-local [docs folder](./docs/) - **🐛 GitHub Issues**: Questions, bug reports, and feature requests - **🔒 Security**: Private security vulnerability reporting diff --git a/action.yml b/action.yml index 01c76fd..277fcf0 100644 --- a/action.yml +++ b/action.yml @@ -127,4 +127,4 @@ branding: # VAULT_SECRET_ID - AppRole secret ID # # AWS Authentication: -# Use aws-actions/configure-aws-credentials@v4 before this action for OIDC +# Use aws-actions/configure-aws-credentials pinned to a reviewed commit before this action for OIDC diff --git a/docs/ACTION_QUICK_REFERENCE.md b/docs/ACTION_QUICK_REFERENCE.md index 114440e..4700617 100644 --- a/docs/ACTION_QUICK_REFERENCE.md +++ b/docs/ACTION_QUICK_REFERENCE.md @@ -3,14 +3,14 @@ ## Installation ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z ``` ## Minimal Example ```yaml - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml env: @@ -43,7 +43,7 @@ ### Dry Run (PR Validation) ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'true' @@ -53,7 +53,7 @@ ### Specific Targets ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml targets: 'Staging,Production' @@ -62,7 +62,7 @@ ### Merge Only ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml merge-only: 'true' @@ -71,7 +71,7 @@ ### With Exit Codes ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'true' @@ -82,7 +82,7 @@ ### Debug Mode ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml log-level: 'debug' @@ -107,16 +107,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml env: @@ -143,7 +143,7 @@ SecretSync supports all environment variables from the CLI. Common ones: ```yaml - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 @@ -221,7 +221,7 @@ Use with `continue-on-error: true` to handle: ```yaml - name: Check Changes id: check - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: dry-run: 'true' exit-code: 'true' @@ -237,8 +237,8 @@ Use with `continue-on-error: true` to handle: ### Config File Not Found ```yaml -- uses: actions/checkout@v4 # Must checkout first! -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: path/to/config.yaml # Relative to repo root ``` @@ -263,7 +263,7 @@ Ensure OIDC is configured correctly and trust policy allows your repository. ```yaml # Recommended: Pin to a package release tag -uses: jbcom/secrets-sync@secretssync-v2.0.2 +uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z # Not recommended: Track the branch tip uses: jbcom/secrets-sync@main diff --git a/docs/ARCHITECTURE_GAP_ANALYSIS.md b/docs/ARCHITECTURE_GAP_ANALYSIS.md index 05a54de..f4d0495 100644 --- a/docs/ARCHITECTURE_GAP_ANALYSIS.md +++ b/docs/ARCHITECTURE_GAP_ANALYSIS.md @@ -1,559 +1,63 @@ -# Architecture Gap Analysis: Terraform Pipeline vs secretsync - -This document provides a comprehensive analysis of the requirements from the original Terraform-based `terraform-aws-secretsmanager` pipeline compared to the current `secretsync` implementation. - -## Executive Summary - -The current implementation has a solid foundation but has **critical gaps** in the merge semantics that would cause behavioral differences from the original pipeline. These must be addressed before the PR can be considered complete. - ---- - -## Part 1: Core Pipeline Behavior Analysis - -### 1.1 Deepmerge Strategy - -**Original Requirement (Part 1):** -```python -self.merger = Merger( - [(list, ["append"]), (dict, ["merge"]), (set, ["union"])], - ["override"], # fallback - ["override"], # type conflict -) -``` - -- **Lists**: APPEND (new items added, not replaced) -- **Dicts**: MERGE (recursive deep merge) -- **Sets**: UNION (combined) -- **Conflicts**: OVERRIDE (later values win) - -**Current Implementation (`stores/vault/vault.go:298-312`):** -```go -if vc.Merge { - sec, err := vc.GetSecret(ctx, s) - // ... - for k, v := range data { - secd[k] = v // SIMPLE OVERRIDE - NOT DEEPMERGE - } - data = secd -} -``` - -**GAP: CRITICAL** ❌ -- Current merge does simple key override: `secd[k] = v` -- Does NOT append lists -- Does NOT recursively merge nested dicts -- This will cause different behavior for secrets like: - ```json - // Source 1: {"tags": ["prod"], "config": {"a": 1}} - // Source 2: {"tags": ["v2"], "config": {"b": 2}} - // Expected: {"tags": ["prod", "v2"], "config": {"a": 1, "b": 2}} - // Current: {"tags": ["v2"], "config": {"b": 2}} // WRONG - ``` - -**Required Fix:** -- Implement proper deepmerge function with list append, dict merge, set union semantics -- Apply in `VaultClient.WriteSecret` when `Merge: true` - ---- - -### 1.2 Vault Secret Listing - -**Original Requirement (Part 1):** -```python -# BFS traversal using deque -# Paths stored WITHOUT leading slash: "api-keys/stripe" not "/api-keys/stripe" -# Directories end with "/" -# Uses KV2 API (secrets.kv.v2) -``` - -**Current Implementation (`stores/vault/vault.go:448-505`):** -```go -func (vc *VaultClient) ListSecretsOnce(ctx context.Context, p string) ([]string, error) { - // Uses metadata path correctly - pp = insertSliceString(pp, 1, "metadata") - // Returns keys from listing -} -``` - -**GAP: MINOR** ⚠️ -- Current implementation lists secrets but doesn't do recursive BFS traversal -- The sync framework handles recursion via regex patterns, but direct listing is flat -- Path format handling appears consistent (no leading slash) - -**Required Fix:** -- Verify path normalization in all code paths -- Consider adding recursive listing helper if needed for direct API usage - ---- - -### 1.3 AWS Secrets Manager Listing - -**Original Requirement (Part 1):** -```python -def list_aws_account_secrets( - self, - filters: Optional[list] = None, - get_secrets: Optional[bool] = None, - no_empty_secrets: Optional[bool] = None, # Skip empty/null secrets - execution_role_arn: Optional[str] = None, -): - # Paginated listing with IncludePlannedDeletion=False - # Skip empty secrets if requested -``` - -**Current Implementation (`stores/aws/aws.go:283-312`):** -```go -func (g *AwsClient) ListSecrets(ctx context.Context, p string) ([]string, error) { - params := &secretsmanager.ListSecretsInput{ - NextToken: nextToken, - } - // Pagination: YES ✓ - // IncludePlannedDeletion: NOT SET - // Filters: NOT SUPPORTED - // no_empty_secrets: NOT SUPPORTED -} -``` - -**GAP: MEDIUM** ⚠️ -- Missing `IncludePlannedDeletion: false` parameter -- Missing `Filters` support -- Missing `no_empty_secrets` option to skip null/empty values -- These can cause sync of deleted/empty secrets - -**Required Fix:** -- Add `IncludePlannedDeletion: aws.Bool(false)` to ListSecretsInput -- Add optional `Filters` parameter -- Add `no_empty_secrets` logic when fetching values - ---- - -### 1.4 Import Source Determination - -**Original Requirement (Part 1 & 3):** -```hcl -# NULL execution_role_arn → Vault mount -# Non-NULL execution_role_arn → AWS account -imports_config = { - for import_source in imports_raw_config : import_source => - try(coalesce(local.accounts_data[import_source]["execution_role_arn"]), null) -} -``` - -**Current Implementation (`pkg/pipeline/config.go:466-482`):** -```go -func (c *Config) GetSourcePath(importName string) string { - // Check if it's a direct source - if src, ok := c.Sources[importName]; ok { - if src.Vault != nil { - return src.Vault.Mount - } - } - // Check if it's another target (inheritance) - if _, ok := c.Targets[importName]; ok { - // ... - } - return importName -} -``` - -**GAP: MEDIUM** ⚠️ -- Current implementation distinguishes Source vs Target -- Does NOT distinguish based on presence of `execution_role_arn` -- The Source struct has both `Vault` and `AWS` fields, but resolution logic doesn't use execution_role_arn as the discriminator - -**Required Fix:** -- Add logic to check if import source has associated AWS account (via accounts lookup) -- If has execution_role_arn → read from AWS SM -- If no execution_role_arn → read from Vault mount - ---- - -### 1.5 Target Inheritance Model - -**Original Requirement (Part 1):** -```yaml -Serverless_Prod: - imports: - - Serverless_Stg # AWS account! Inherits CURRENT state from AWS - -# For secretsync using merge store: -# 1. Merge: analytics + analytics-engineers → merged-secrets/Serverless_Stg/ -# 2. Merge: merged-secrets/Serverless_Stg/ → merged-secrets/Serverless_Prod/ -# 3. Sync: merged-secrets/Serverless_Stg/ → AWS Serverless_Stg -# 4. Sync: merged-secrets/Serverless_Prod/ → AWS Serverless_Prod -``` - -**Current Implementation (`pkg/pipeline/config.go:451-463`):** -```go -func (c *Config) IsInheritedTarget(targetName string) bool { - target, ok := c.Targets[targetName] - for _, imp := range target.Imports { - if _, isTarget := c.Targets[imp]; isTarget { - return true // Correctly identifies inheritance - } - } - return false -} -``` - -**GAP: MINOR** ✓ -- Inheritance detection is implemented correctly -- `GetSourcePath` correctly returns merge store path for inherited targets -- Dependency graph correctly orders operations - -**Status: IMPLEMENTED** ✓ - ---- - -### 1.6 Path Conflict Handling (/foo vs foo) - -**Original Requirement (Part 1):** -```python -def sync_secret(self, client, secret_name: str, secret_value: Any): - # Handle path conflicts (with and without leading /) - alternate_path = secret_name[1:] if secret_name.startswith('/') else f'/{secret_name}' - if self.handle_deleted_secret(client, alternate_path) is not None: - self.safe_delete_secret(client, alternate_path) -``` - -**Current Implementation:** -- No explicit path conflict handling found in `stores/aws/aws.go` -- No normalization of leading slash - -**GAP: MEDIUM** ⚠️ -- Secrets could be duplicated with different path formats -- `/prod/database` and `prod/database` would be treated as different secrets - -**Required Fix:** -- Add path normalization function -- Before creating secret, check for alternate path format -- Delete conflicting alternate if exists - ---- - -### 1.7 JSON-Aware Comparison (Idempotency) - -**Original Requirement (Part 1):** -```python -def compare_secret_values(self, existing: str, new: str) -> bool: - """Compare as JSON if possible, otherwise string compare""" - try: - return json.loads(existing) == json.loads(new) - except json.JSONDecodeError: - return existing == new -``` - -**Current Implementation:** -- Sync always writes without comparison -- No idempotency check found - -**GAP: MEDIUM** ⚠️ -- Unnecessary writes to AWS SM -- Could trigger change events unnecessarily -- Higher API costs - -**Required Fix:** -- Before WriteSecret, compare existing value with new value -- Use JSON-aware comparison for dict/list secrets -- Skip write if values are equivalent - ---- - -## Part 2: tm_cli Interface Analysis - -### 2.1 Vault Authentication - -**Original Requirement (Part 2):** -```python -# Try token auth first -if vault_token and self._vault_client.is_authenticated(): - return self._vault_client -# Fallback to AppRole -if role_id and secret_id: - self._vault_client.auth.approle.login(...) -``` - -**Current Implementation (`stores/vault/vault.go:186-208`):** -```go -func (vc *VaultClient) NewToken(ctx context.Context) error { - if os.Getenv("VAULT_TOKEN") != "" { - vc.Client.SetToken(os.Getenv("VAULT_TOKEN")) - } - if err := vc.Login(ctx); err != nil { - return err - } -} -``` - -**GAP: MINOR** ✓ -- Token auth supported via VAULT_TOKEN env var -- Kubernetes auth supported -- AppRole not directly visible but can be added via AuthMethod - -**Status: MOSTLY IMPLEMENTED** ✓ -- Could add explicit AppRole support if needed - ---- - -### 2.2 Allowlist/Denylist Filtering - -**Original Requirement (Part 2):** -```python -if allowlist: - merged_data = {k: v for k, v in merged_data.items() if k in allowlist} -if denylist: - merged_data = {k: v for k, v in merged_data.items() if k not in denylist} -``` - -**Current Implementation (`internal/transforms/filter.go`):** -- Filter transforms exist for include/exclude patterns -- Applied at sync level via SecretSync spec - -**GAP: MINOR** ✓ -- Filtering available via transforms -- Syntax different but equivalent functionality - -**Status: IMPLEMENTED** ✓ (via transforms) - ---- - -### 2.3 Error Handling (Resilience) - -**Original Requirement (Part 2):** -```python -except InvalidPath as exc: - self.logger.warning(f"Invalid secret path {current_path}: {exc}") - # Continues to next secret, doesn't fail entire operation -``` - -**Current Implementation (`pkg/pipeline/pipeline.go:425-433`):** -```go -for _, r := range levelResults { - if !r.Success { - lastErr = r.Error - if !opts.ContinueOnError { - return results, lastErr - } - } -} -``` - -**GAP: MINOR** ✓ -- `ContinueOnError` option exists -- Errors logged and tracked -- Pipeline continues on failure if configured - -**Status: IMPLEMENTED** ✓ - ---- - -## Part 3: Configuration Format Analysis - -### 3.1 Config File Formats - -**Original Requirement (Part 3):** -```yaml -# Two syntax formats: -# 1. Explicit: target: {imports: [list]} -# 2. Shorthand: target: [list] # list IS the imports - -Serverless_Stg: - imports: - - analytics - -Serverless_Prod: - - Serverless_Stg # Shorthand -``` - -**Current Implementation (`pkg/pipeline/config.go`):** -- Only supports explicit format: `imports: [...]` -- YAML unmarshaling doesn't handle shorthand - -**GAP: MEDIUM** ⚠️ -- Migration from terraform-aws-secretsmanager configs won't work directly -- Users must manually convert shorthand to explicit format - -**Required Fix:** -- Add custom YAML unmarshaler for Target struct -- Detect if value is list (shorthand) vs map (explicit) -- Convert shorthand to explicit format during load - ---- - -### 3.2 accounts_by_json_key Integration - -**Original Requirement (Part 3):** -```json -{ - "Serverless_Stg": { - "account_id": "654654379445", - "execution_role_arn": "arn:aws:iam::654654379445:role/AWSControlTowerExecution", - "environment": "staging", - "ou_path": "Sandboxes/Analytics" - } -} -``` - -**Current Implementation:** -- No direct accounts_by_json_key lookup -- Account info embedded in Target struct -- Dynamic discovery via Organizations/Identity Center - -**GAP: MINOR** ⚠️ -- Different approach: static config vs dynamic discovery -- Migration command should map old format to new - -**Status: DIFFERENT APPROACH** - acceptable if migrate command handles conversion - ---- - -### 3.3 S3 Intermediate Storage - -**Original Requirement (Part 3):** -```python -s3_key = f"secrets/{target_account_id}.json" -s3.put_object( - Bucket=secrets_bucket, - Key=s3_key, - Body=json.dumps(merged_secrets) -) -``` - -**Current Implementation (`pkg/pipeline/s3_store.go`):** -```go -func (s *S3MergeStore) keyPath(targetName string) string { - if s.config.Prefix != "" { - return fmt.Sprintf("%s/%s.json", s.config.Prefix, targetName) - } - return fmt.Sprintf("secrets/%s.json", targetName) -} -``` - -**GAP: MINOR** ✓ -- S3 storage implemented -- Key format matches (`secrets/{target}.json`) -- Encryption supported (KMS or AES256) - -**Status: IMPLEMENTED** ✓ - ---- - -### 3.4 SSM Parameter Store Discovery - -**Original Requirement (Part 3):** -- External account lists from SSM Parameter Store -- Pattern: `ssm:/platform/analytics-engineer-sandboxes` - -**Current Implementation (`pkg/pipeline/discovery.go:297-309`):** -```go -func (d *DiscoveryService) getAccountsFromSSM(paramName string) ([]AccountInfo, error) { - // Placeholder - returns error - return nil, fmt.Errorf("SSM-based account discovery requires SSM client setup; parameter: %s", paramName) -} -``` - -**GAP: MEDIUM** ⚠️ -- Feature documented but not implemented -- Returns placeholder error - -**Required Fix:** -- Implement SSM client in AWSExecutionContext -- Parse parameter value (comma-separated or JSON array) -- Convert to AccountInfo list - ---- - -## Summary: Gap Resolution Status - -### CRITICAL - RESOLVED ✅ - -| # | Gap | File | Status | -|---|-----|------|--------| -| 1 | **Deepmerge semantics** | `stores/vault/vault.go`, `pkg/utils/deepmerge.go` | ✅ **FIXED** - Implemented proper deepmerge with list append, dict merge, set union | - -### HIGH - RESOLVED ✅ - -| # | Gap | File | Status | -|---|-----|------|--------| -| 2 | Path conflict handling | `stores/aws/aws.go` | ✅ **FIXED** - Added `getAlternatePath()` and conflict detection in `WriteSecret()` | -| 3 | JSON-aware comparison | `stores/aws/aws.go`, `pkg/utils/deepmerge.go` | ✅ **FIXED** - Added `CompareSecretsJSON()` and `SkipUnchanged` option | -| 4 | no_empty_secrets | `stores/aws/aws.go` | ✅ **FIXED** - Added `NoEmptySecrets` field and `isSecretEmpty()` check | -| 5 | IncludePlannedDeletion | `stores/aws/aws.go` | ✅ **FIXED** - Added `IncludePlannedDeletion: aws.Bool(false)` to `ListSecrets()` | - -### MEDIUM - RESOLVED ✅ - -| # | Gap | File | Status | -|---|-----|------|--------| -| 6 | Shorthand config format | `pkg/pipeline/config.go` | ✅ **FIXED** - Added `UnmarshalYAML` custom unmarshaler for Target | -| 7 | SSM discovery | `pkg/pipeline/discovery.go`, `pkg/pipeline/aws_context.go` | ✅ **FIXED** - Implemented `GetSSMParameter()` and full `getAccountsFromSSM()` | -| 8 | Import source resolution by execution_role_arn | `pkg/pipeline/config.go` | ⚠️ **DEFERRED** - Current approach uses Source type (Vault/AWS) which is clearer | - ---- - -## Implementation Status - -### Phase 1: Critical Fix ✅ COMPLETE - -1. **Implement proper deepmerge in Vault store** ✅ - - Created `pkg/utils/deepmerge.go` with proper semantics - - Lists: append ✅ - - Dicts: recursive merge ✅ - - Sets: union ✅ - - Conflicts: override ✅ - - Integrated into `VaultClient.WriteSecret` ✅ - - Added comprehensive unit tests in `pkg/utils/deepmerge_test.go` ✅ - -### Phase 2: High Priority Fixes ✅ COMPLETE - -2. **Path normalization in AWS store** ✅ - - Added `getAlternatePath()` function - - Check for alternate format before create in `WriteSecret()` - - Delete conflicting alternate if exists - -3. **Idempotency with JSON comparison** ✅ - - Added `CompareSecretsJSON()` function in `pkg/utils/deepmerge.go` - - Added `SkipUnchanged` option to `AwsClient` - - Check before write, skip if equivalent - -4. **AWS listing improvements** ✅ - - Added `IncludePlannedDeletion: aws.Bool(false)` to ListSecretsInput - - Added `NoEmptySecrets` option and `isSecretEmpty()` check - -### Phase 3: Medium Priority Fixes ✅ COMPLETE - -5. **Shorthand config support** ✅ - - Added custom `UnmarshalYAML` for Target struct - - Supports both `{imports: [...]}` and `[list]` formats - -6. **SSM discovery** ✅ - - Added `ssmClient` to AWSExecutionContext - - Added `GetSSMParameter()` method - - Implemented full `getAccountsFromSSM()` with support for: - - Comma-separated lists - - JSON string arrays - - JSON object arrays with id/name fields - ---- - -## Verification Checklist - -All items verified: - -- [x] Deepmerge: `{"tags": ["a"]}` + `{"tags": ["b"]}` = `{"tags": ["a", "b"]}` (unit test: TestDeepMerge_ListAppend) -- [x] Deepmerge: `{"config": {"x": 1}}` + `{"config": {"y": 2}}` = `{"config": {"x": 1, "y": 2}}` (unit test: TestDeepMerge_DictMerge) -- [x] Path handling: `/foo` and `foo` don't create duplicates (getAlternatePath + WriteSecret) -- [x] Idempotency: Unchanged secrets don't trigger writes (SkipUnchanged + CompareSecretsJSON) -- [x] Empty secrets: Not synced when no_empty_secrets is set (NoEmptySecrets + isSecretEmpty) -- [x] Deleted secrets: Not synced (IncludePlannedDeletion=false) -- [x] Inheritance: Serverless_Prod correctly inherits from Serverless_Stg (IsInheritedTarget + GetSourcePath) -- [x] Dynamic targets: Organizations discovery works (DiscoveryService) -- [x] S3 merge store: Secrets written to correct path (S3MergeStore) -- [x] Error resilience: Pipeline continues on single secret failure (ContinueOnError) -- [x] Shorthand config: Both `{imports: [...]}` and `[list]` formats supported -- [x] SSM discovery: Accounts can be loaded from SSM Parameter Store - -## Build & Test Status - -- ✅ `go build ./...` - PASSED -- ✅ `go test ./...` - ALL PASSED -- ✅ `golangci-lint run` - 0 ISSUES +# Architecture Audit + +This file records the current architecture status of the standalone +`jbcom/secrets-sync` repository. It replaces the earlier migration-era gap +analysis that referenced old monorepo paths such as `stores/vault/vault.go`. + +## Current Shape + +SecretSync is a standalone Go module with: + +- CLI entry point in `cmd/secretsync`. +- Pipeline orchestration in `pkg/pipeline`. +- Vault and AWS clients in `pkg/client`. +- Diffing and exit-code behavior in `pkg/diff`. +- Circuit breaker, request context, and observability support in `pkg`. +- Docker action metadata in `action.yml`. +- Optional Python binding sources under `python/secretssync`. +- Kubernetes API types under `api/v1alpha1`. + +The main runtime path is the two-phase pipeline: + +1. Merge source secrets into a deterministic merge-store bundle. +2. Sync the bundle into destination stores, primarily AWS Secrets Manager. + +## Implemented Parity Items + +| Area | Current status | Primary implementation | +| --- | --- | --- | +| Deep merge semantics | Implemented: maps merge recursively, lists append, scalar and type conflicts override. | `pkg/utils/deepmerge.go`, `pkg/pipeline/merge.go`, `pkg/client/vault/vault.go` | +| Vault KV2 traversal | Implemented with breadth-first recursive listing, path validation, depth limits, secret-count limits, and queue compaction. | `pkg/client/vault/vault.go` | +| AWS planned-deletion filtering | Implemented with `IncludePlannedDeletion: aws.Bool(false)`. | `pkg/client/aws/aws.go` | +| Empty AWS secret filtering | Implemented through `NoEmptySecrets`. | `pkg/client/aws/aws.go` | +| Path conflict handling | Implemented for `/foo` versus `foo` before writes. | `pkg/client/aws/aws.go` | +| JSON-aware idempotency | Implemented through `SkipUnchanged` and JSON-normalized comparison. | `pkg/client/aws/aws.go`, `pkg/utils/deepmerge.go` | +| Target inheritance | Implemented with cycle detection and merge-store source paths. | `pkg/pipeline/inheritance.go`, `pkg/pipeline/graph.go` | +| Diff exit codes | Implemented and tested: no changes, changes, and error states map to stable exit codes. | `pkg/diff`, `pkg/pipeline/diff_integration_test.go` | +| Stable pipeline result output | Implemented for machine-readable action and CLI use. | `cmd/secretsync/cmd`, `pkg/pipeline` | + +## Release And Action Status + +- CI and release workflows are SHA-pinned to current stable action releases. +- Release-please owns the `secrets-sync-vX.Y.Z` component tag shape. +- GoReleaser builds binary release artifacts from release-created tags. +- The Docker action image tag remains `jbcom/secretssync:v1` until digest + refresh can be automated. + +## Known Remaining Work + +- Some historical docs still describe webhook/operator deployment models. Treat + those pages as legacy unless they are refreshed against the current CLI + pipeline. +- The Marketplace and action docs should continue to use the component release + tag placeholder until the first standalone repository release exists. +- The Docker action should eventually move to a digest-pinned image reference + once release automation can update that digest as part of publication. +- Optional Python binding and Kubernetes API surfaces need separate release + contracts if they become first-class artifacts. + +## Development Rule + +Prefer visible breakage over compatibility shims. This repository is a clean +standalone line, so stale monorepo assumptions should be removed or made to fail +in tests rather than silently accepted. diff --git a/docs/FAQ.md b/docs/FAQ.md index 8c3e4fb..c7335d0 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -231,7 +231,7 @@ Use the GitHub Action: ```yaml - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'false' diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index b8d2745..1d78894 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -219,16 +219,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml env: diff --git a/docs/GITHUB_ACTIONS.md b/docs/GITHUB_ACTIONS.md index a3e1be6..4a2b82f 100644 --- a/docs/GITHUB_ACTIONS.md +++ b/docs/GITHUB_ACTIONS.md @@ -21,16 +21,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml ``` @@ -81,16 +81,16 @@ jobs: pull-requests: write # For PR comments steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Validate Changes (Dry Run) - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'true' @@ -128,16 +128,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml targets: ${{ github.event.inputs.targets != 'all' && github.event.inputs.targets || '' }} @@ -163,10 +163,10 @@ jobs: merge: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Merge Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml merge-only: 'true' @@ -195,16 +195,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync with Discovery - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml discover: 'true' @@ -235,17 +235,17 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Check for Changes id: check - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'true' @@ -258,7 +258,7 @@ jobs: - name: Apply Changes if: steps.check.outcome == 'failure' - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml output-format: 'github' @@ -295,16 +295,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: configs/${{ github.event.inputs.environment }}.yaml output-format: 'github' @@ -363,7 +363,7 @@ targets: **Recommended:** ```yaml - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 @@ -396,7 +396,7 @@ jobs: sync-production: environment: production # Requires approval steps: - - uses: jbcom/secrets-sync@secretssync-v2.0.2 + - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: production.yaml ``` @@ -516,9 +516,9 @@ Example policy: Ensure your config file is in the repository and the path is correct: ```yaml -- uses: actions/checkout@v4 # Required to access repository files +- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: path/to/config.yaml # Relative to repo root ``` @@ -528,7 +528,7 @@ Ensure your config file is in the repository and the path is correct: Verify environment variables are set correctly: ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml log-level: debug # Enable debug logging @@ -550,7 +550,7 @@ Check: Ensure `output-format` is set to `github`: ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: output-format: 'github' # Enables GitHub Actions annotations ``` @@ -570,7 +570,7 @@ Example using exit codes: ```yaml - name: Check for Changes id: check - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: dry-run: 'true' exit-code: 'true' @@ -603,16 +603,16 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets[format('AWS_ROLE_{0}', matrix.environment)] }} aws-region: us-east-1 - name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: configs/${{ matrix.environment }}.yaml ``` @@ -632,7 +632,7 @@ jobs: sync: if: github.ref == 'refs/heads/main' steps: - - uses: jbcom/secrets-sync@secretssync-v2.0.2 + - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z ``` ### Composite Actions @@ -650,12 +650,12 @@ inputs: runs: using: composite steps: - - uses: aws-actions/configure-aws-credentials@v4 + - uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - - uses: jbcom/secrets-sync@secretssync-v2.0.2 + - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: ${{ inputs.config }} output-format: 'github' diff --git a/docs/MARKETPLACE.md b/docs/MARKETPLACE.md index 53d4529..5524da1 100644 --- a/docs/MARKETPLACE.md +++ b/docs/MARKETPLACE.md @@ -1,358 +1,164 @@ -# GitHub Marketplace Listing Guide +# GitHub Marketplace Guide -This document provides information for listing SecretSync on the GitHub Marketplace as a verified free action. +This guide describes the GitHub Marketplace surface for the standalone +`jbcom/secrets-sync` action. -## Marketplace Information +## Listing Summary -### Basic Information +| Field | Value | +| --- | --- | +| Name | `SecretSync` | +| Repository | `jbcom/secrets-sync` | +| Category | Deployment, Continuous Integration, Security | +| License | MIT | +| Pricing | Free | -**Name**: SecretSync -**Tagline**: Universal secrets synchronization pipeline for multi-cloud secret management -**Category**: Deployment and Continuous Integration -**Pricing**: Free +SecretSync synchronizes secrets from HashiCorp Vault into AWS Secrets Manager +with a two-phase merge and sync pipeline. It is designed for multi-account AWS +environments, AWS Organizations discovery, and CI/CD validation workflows. -### Description +## Supported Runtime Surface -SecretSync provides fully automated, real-time secret synchronization between HashiCorp Vault and AWS. Perfect for multi-account AWS environments, HashiCorp Vault users, and organizations managing secrets across AWS Organizations. - -**Key Features:** -- 🔄 Two-phase pipeline architecture (merge → sync) -- 🎯 Vault-to-AWS secrets synchronization -- 🌐 Multi-account AWS secret management -- 📊 GitHub-native diff annotations in PRs -- 🔒 OIDC authentication for AWS (no long-lived credentials) -- 🚀 Dynamic target discovery via AWS Organizations/Identity Center -- ⚡ Zero-configuration Docker action -- 🔐 Complete privacy - no data collection - -### Supported Stores - -- HashiCorp Vault (KV2) - source -- AWS Secrets Manager - target -- AWS S3 (merge store option) -- Kubernetes Secrets (operator mode) - -## Marketplace Requirements Checklist - -### ✅ Technical Requirements - -- [x] **action.yml file**: Present in repository root -- [x] **Docker-based action**: Uses Dockerfile for containerization -- [x] **Valid inputs**: All inputs properly documented with descriptions -- [x] **Branding**: Icon and color specified -- [x] **Multi-arch support**: Supports linux/amd64 and linux/arm64 - -### ✅ Documentation Requirements - -- [x] **README.md**: Comprehensive documentation with examples -- [x] **Usage examples**: Complete workflow examples -- [x] **Input documentation**: All inputs documented with defaults -- [x] **Quick start guide**: Easy getting started section -- [x] **Advanced examples**: Multiple use case examples - -### ✅ Legal and Policy Requirements - -- [x] **License**: MIT License (permissive, OSI-approved) -- [x] **Privacy Policy**: See [docs/PRIVACY.md](./PRIVACY.md) -- [x] **Support Information**: See [docs/SUPPORT.md](./SUPPORT.md) -- [x] **Security Policy**: See [docs/SECURITY.md](./SECURITY.md) -- [x] **Code of Conduct**: Implicit in professional conduct - -### ✅ Quality Requirements - -- [x] **Working action**: Fully functional and tested -- [x] **Error handling**: Proper error messages and exit codes -- [x] **Logging**: Comprehensive logging with multiple formats -- [x] **Security**: No hardcoded secrets, proper secret handling -- [x] **Performance**: Efficient execution with parallel processing - -### ✅ Marketplace Best Practices - -- [x] **Semantic versioning**: Using git tags (v1, v1.0.0, etc.) -- [x] **Clear naming**: Descriptive and searchable name -- [x] **Useful description**: Clear value proposition -- [x] **Good documentation**: Step-by-step guides and examples -- [x] **Community support**: GitHub Issues -- [x] **Regular updates**: Active maintenance and improvements - -## Publishing to Marketplace - -### Prerequisites - -1. **Repository Requirements** - - Public repository on GitHub - - Valid `action.yml` in root directory - - Proper branding (icon, color) - - Comprehensive README - -2. **Legal Requirements** - - License file (MIT) - - Privacy policy - - Support contact information - - Security policy - -3. **Quality Requirements** - - Working action with examples - - No security vulnerabilities - - Proper error handling - - Good documentation - -### Publishing Steps - -1. **Verify Action Works** - ```bash - # Test action locally - act -j test-action - ``` - -2. **Create Version Tags** - ```bash - # Create and push version tags - git tag -a v1.0.0 -m "Release v1.0.0" - git push origin v1.0.0 - - # Create major version tag (recommended for users) - git tag -fa v1 -m "Release v1" - git push origin v1 --force - ``` - -3. **Publish to Marketplace** - - Go to repository on GitHub - - Click "Releases" - - Click "Draft a new release" - - Choose the version tag (e.g., v1.0.0) - - Check "Publish this Action to the GitHub Marketplace" - - Select primary category: "Deployment" - - Add release notes - - Click "Publish release" - -4. **Verify Listing** - - Visit: https://github.com/marketplace/actions/secretsync - - Verify all information is correct - - Test the action from Marketplace - -### Recommended Version Tags +- GitHub Action using `action.yml`. +- Docker image `jbcom/secretssync:v1`. +- Go CLI `secretsync`. +- Vault KV2 sources. +- AWS Secrets Manager targets. +- Vault or S3 merge stores. +- GitHub-native output for PR validation and CI logs. -```bash -# Semantic version (specific) -v1.0.0, v1.0.1, v1.1.0, v2.0.0 - -# Major version (for users - auto-updates) -v1, v2 - -# Example: Release v1.2.3 -git tag -a v1.2.3 -m "Release v1.2.3 - Add OIDC support" -git push origin v1.2.3 +Avoid advertising stores or deployment modes that are not implemented in the +current standalone repository. -# Update major version pointer -git tag -fa v1 -m "Update v1 to v1.2.3" -git push origin v1 --force -``` - -## Marketplace Metadata +## Release Tags -### Action Metadata (action.yml) +Release-please manages releases for the root package named `secrets-sync`. +Marketplace examples should therefore use component release tags: ```yaml -name: 'SecretSync' -description: 'Universal secrets synchronization pipeline for multi-cloud secret management with Vault, AWS, GCP, and more' -author: 'jbcom' - -branding: - icon: 'lock' - color: 'blue' +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z ``` -### Category Selection - -**Primary Category**: Deployment -**Additional Categories**: -- Continuous Integration -- Security -- Utilities - -### Tags/Keywords - -- secrets-management -- vault -- aws-secrets-manager -- secret-sync -- multi-cloud -- devops -- security -- oidc -- ci-cd -- github-actions - -## Marketing Copy - -### Short Description (200 chars) - -Vault-to-AWS secrets sync. Two-phase pipeline with inheritance, dynamic discovery via AWS Organizations/Identity Center & GitHub-native diffs. Free, open source. - -### Long Description - -SecretSync revolutionizes Vault-to-AWS secrets management with a powerful two-phase pipeline architecture. Built for organizations managing secrets across multiple AWS accounts with HashiCorp Vault as the source of truth. - -**Perfect For:** -- Multi-account AWS environments (Control Tower, Organizations) -- HashiCorp Vault users syncing to AWS Secrets Manager -- Teams managing secrets across dev/staging/prod -- Organizations requiring secret inheritance hierarchies -- DevOps teams automating secret distribution - -**Key Benefits:** - -🔄 **Two-Phase Architecture** -Merge secrets from multiple Vault paths, then sync to multiple AWS accounts with inheritance support. - -🎯 **Vault → AWS Sync** -HashiCorp Vault (KV2) as source, AWS Secrets Manager as target, with S3 or Vault merge store options. - -🌐 **AWS-Native Patterns** -First-class support for AWS Control Tower, Organizations, and Identity Center patterns. - -📊 **GitHub-Native Integration** -Automatic PR annotations, diff reporting, and status checks. - -🔒 **Security First** -OIDC authentication, no long-lived credentials, complete audit trail, zero data collection. +Do not document old monorepo package tags using the `secretssync-v...` shape. -🚀 **Dynamic Discovery** -Automatically discover and sync to accounts via AWS Organizations or Identity Center. +`@main` may be useful for development testing, but it is not a stable +Marketplace recommendation. Moving major aliases such as `@v1` should only be +documented if the repository intentionally creates and maintains those aliases. -**Use Cases:** +## Marketplace Requirements -1. **Control Tower Environments**: Sync secrets to all AWS accounts in your organization -2. **Vault Distribution**: Push Vault secrets to AWS Secrets Manager across accounts -3. **Secret Inheritance**: Dev → Staging → Production with automatic propagation -4. **Multi-Region**: Sync secrets across AWS regions from central Vault -5. **Compliance**: Automated secret rotation with complete audit trail +- Repository is public. +- `action.yml` exists in the repository root. +- Action metadata has name, description, author, inputs, branding, and Docker + image reference. +- README includes a working action example. +- `LICENSE`, `SECURITY.md`, `CONTRIBUTING.md`, privacy docs, and support docs + are present. +- Workflow examples use least-privilege permissions. +- Third-party actions in maintained examples are pinned to exact commit SHAs. -**Zero Configuration** -Just add your config file and secrets - the action handles the rest. +## Publication Flow -## Badge and Shield Links +1. Merge normal changes to `main` using Conventional Commit prefixes. +2. Let release-please open or update the release PR. +3. Merge the release PR after review. +4. Confirm the release workflow created a `secrets-sync-vX.Y.Z` GitHub release. +5. Confirm GoReleaser uploaded binary assets and `checksums.txt`. +6. In the GitHub release UI, publish that release to Marketplace. +7. Verify the Marketplace page renders the README and action metadata correctly. -Add these to README for visibility: +Do not create a manual release or manual version tag during normal publication. -```markdown -[![GitHub Marketplace](https://img.shields.io/badge/Marketplace-SecretSync-blue.svg?colorA=24292e&colorB=0366d6&style=flat&longCache=true&logo=github)](https://github.com/marketplace/actions/secretsync) +## Recommended Usage Snippet -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - -[![GitHub release](https://img.shields.io/github/v/release/jbcom/secrets-sync?filter=secretssync-v*&label=release)](https://github.com/jbcom/secrets-sync/releases) - -[![GitHub stars](https://img.shields.io/github/stars/jbcom/secrets-sync.svg)](https://github.com/jbcom/secrets-sync/stargazers) +```yaml +name: Sync Secrets + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-east-1 + + - name: Sync Secrets + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z + with: + config: config.yaml + output-format: github + env: + VAULT_ROLE_ID: ${{ secrets.VAULT_ROLE_ID }} + VAULT_SECRET_ID: ${{ secrets.VAULT_SECRET_ID }} ``` -## Support URLs - -Add these to the Marketplace listing: - -- **Documentation**: https://github.com/jbcom/secrets-sync/docs -- **Issues**: https://github.com/jbcom/secrets-sync/issues -- **Support**: https://github.com/jbcom/secrets-sync/blob/main/docs/SUPPORT.md -- **Privacy Policy**: https://github.com/jbcom/secrets-sync/blob/main/docs/PRIVACY.md -- **Security**: https://github.com/jbcom/secrets-sync/blob/main/docs/SECURITY.md - -## Verification Requirements - -For verified publisher status: - -1. **Organization Account**: Must be published from an organization (not personal) -2. **Email Verification**: Organization email must be verified -3. **2FA Enabled**: Two-factor authentication required -4. **Quality Standards**: Meet all GitHub Marketplace quality requirements -5. **Active Maintenance**: Regular updates and responsive support - -## Monitoring and Maintenance - -### Post-Publication Tasks - -1. **Monitor Issues**: Respond to bug reports and questions -2. **Track Usage**: Use GitHub's marketplace insights -3. **Regular Updates**: Keep action up-to-date with dependencies -4. **Security Patches**: Respond quickly to security issues -5. **Documentation**: Keep docs updated with new features +## Metadata -### Marketplace Insights +`action.yml` should remain the source of truth for action metadata: -Track these metrics: -- Daily/monthly active users -- Total installations -- Popular use cases (from issues and support requests) -- User feedback and ratings -- Common problems/questions - -## Compliance and Policies - -### Data Privacy - -SecretSync is privacy-by-design: -- ✅ No data collection -- ✅ No external network calls (except to user's configured services) -- ✅ No telemetry or analytics -- ✅ Complete user control -- ✅ Open source and auditable - -See [Privacy Policy](./PRIVACY.md) for details. - -### Security - -- Regular dependency updates -- CodeQL scanning enabled -- Security policy documented -- Responsible disclosure process -- No known vulnerabilities - -See [Security Policy](./SECURITY.md) for details. +```yaml +name: "SecretSync" +author: "jbcom" +description: "Sync secrets from HashiCorp Vault to AWS Secrets Manager across multiple accounts" +branding: + icon: "lock" + color: "blue" +``` -### Support +## Listing Copy -- GitHub Issues for bug reports -- GitHub Issues for Q&A -- Email for security issues -- Community-driven support +Use concise copy that matches the implementation: -See [Support Guide](./SUPPORT.md) for details. +> SecretSync syncs HashiCorp Vault secrets into AWS Secrets Manager across +> multiple AWS accounts. It supports merge-first pipelines, AWS Organizations +> discovery, dry-run diff output, and GitHub-native CI feedback. -## Frequently Asked Questions +## Verification -### Can I publish beta/pre-release versions? +After publication: -Yes! Use pre-release tags: ```bash -git tag -a v1.0.0-beta.1 -m "Beta release" +gh release view secrets-sync-vX.Y.Z --repo jbcom/secrets-sync +gh workflow run ci.yml --repo jbcom/secrets-sync ``` -### How do I unpublish from Marketplace? - -You can delist the action in your repository settings under "Marketplace". +Also check: -### Can I charge for this action? +- Marketplace page links to the standalone repository. +- The README usage example references `secrets-sync-vX.Y.Z`. +- Inputs shown by Marketplace match `action.yml`. +- No docs mention old `secretssync-v...` monorepo package tags. -This action is MIT licensed and free. Paid versions require different licensing. +## FAQ -### How do version tags work? +### Can users pin `@main`? -Users can reference: -- `@secretssync-v2.0.2` - Current package release tag (recommended) -- `@secretssync-vX.Y.Z` - Exact package release tag (pinned) -- `@main` - Latest commit (not recommended) +They can, but documentation should recommend a component release tag because +`main` is mutable. -### What if my action has dependencies? +### Should we publish a `v1` alias? -Docker actions (like this one) bundle all dependencies in the container. +Only if maintainers decide to update that alias intentionally for every +compatible release. Release-please will not maintain it automatically. -## Additional Resources +### Does the Marketplace release publish binary assets? -- [GitHub Actions Documentation](https://docs.github.com/en/actions) -- [Creating a Docker Container Action](https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action) -- [Publishing Actions to Marketplace](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace) -- [Marketplace Requirements](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace#requirements-for-publishing-an-action) -- [Action Metadata Syntax](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions) +No. GoReleaser publishes binary archives and checksums from the release +workflow. Marketplace publication exposes the action metadata from the GitHub +release. ---- +### Does the action send data to jbcom? -**Ready to publish?** Follow the Publishing Steps above and your action will be live on the GitHub Marketplace! +No. The action runs in the user's GitHub Actions environment and talks directly +to the configured Vault and AWS accounts. See `docs/PRIVACY.md`. diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index c8531cc..802db9e 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -352,15 +352,15 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: aws-actions/configure-aws-credentials@v4 + - uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Run Pipeline - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml targets: ${{ inputs.targets || '' }} diff --git a/docs/PUBLISHING_CHECKLIST.md b/docs/PUBLISHING_CHECKLIST.md index 31c263c..84db35c 100644 --- a/docs/PUBLISHING_CHECKLIST.md +++ b/docs/PUBLISHING_CHECKLIST.md @@ -1,316 +1,114 @@ -# Publishing SecretSync to GitHub Marketplace - Checklist +# Publishing Checklist -This is a step-by-step checklist for publishing SecretSync to the GitHub Marketplace. +SecretSync releases are automated from `main` with release-please and +GoReleaser. Do not hand-edit versions, changelog entries, release tags, or +GitHub releases during the normal release path. -## Pre-Publishing Checklist +## Release Model -### ✅ Repository Requirements +- `release-please` owns version detection, changelog updates, release PRs, and + Git tags. +- The root package name is `secrets-sync`, so component release tags use the + `secrets-sync-vX.Y.Z` shape. +- GoReleaser runs only after release-please reports that a release was created. +- GoReleaser builds binary archives and checksums. Container and Marketplace + publication are separate release surfaces. +- The Docker action currently references `docker://jbcom/secretssync:v1` from + `action.yml`; digest pinning should be added only when release automation can + refresh that digest reliably. -- [x] Repository is public -- [x] `action.yml` exists in repository root -- [x] Action has valid metadata (name, description, author) -- [x] Branding is configured (icon: lock, color: blue) -- [x] Dockerfile builds successfully -- [x] README has usage examples -- [x] LICENSE file exists (MIT) +## Maintainer Preflight -### ✅ Action Configuration - -- [x] All inputs documented with descriptions -- [x] Default values specified for optional inputs -- [x] Docker image reference is correct (`image: 'Dockerfile'`) -- [x] Entrypoint script is executable -- [x] Environment variables properly mapped - -### ✅ Documentation - -- [x] README.md is comprehensive -- [x] Usage examples provided -- [x] Input parameters documented -- [x] Example workflows included -- [x] Security best practices documented -- [x] Troubleshooting section exists - -### ✅ Legal and Compliance - -- [x] MIT License in place -- [x] Privacy policy created (docs/PRIVACY.md) -- [x] Support documentation created (docs/SUPPORT.md) -- [x] Security policy exists (docs/SECURITY.md) -- [x] Contributing guidelines created (CONTRIBUTING.md) - -### ✅ Quality Assurance - -- [x] Action inputs validated -- [x] Entrypoint script syntax validated -- [x] Example configurations provided -- [x] Error handling implemented -- [x] Logging configured -- [x] No hardcoded secrets - -## Publishing Steps - -### Step 1: Final Testing - -Before publishing, test the action: +Run these before merging a release PR or manually dispatching release workflow +diagnostics: ```bash -# 1. Validate entrypoint script -sh -n entrypoint.sh - -# 2. Test Docker build (if environment allows) +go test ./... +go build -o bin/secretsync ./cmd/secretsync +goreleaser check docker build -t secretsync-test . - -# 3. Create a test workflow in .github/workflows/test-action.yml -# Example test workflow: -``` - -```yaml -name: Test Action -on: [push] -jobs: - test: - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - steps: - - uses: actions/checkout@v4 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Test Action - uses: ./ - with: - config: examples/action-test-config.yaml - dry-run: 'true' - env: - VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} ``` -### Step 2: Create Version Tag +If `goreleaser` is not installed locally, use the pinned workflow action as the +source of truth and verify the GitHub check output. -```bash -# 1. Ensure all changes are committed -git status - -# 2. Create annotated tag for first release -git tag -a v1.0.0 -m "Release v1.0.0 - Initial GitHub Marketplace release" - -# 3. Push tag to GitHub -git push origin v1.0.0 - -# 4. Create major version tag (for users) -git tag -fa v1 -m "Release v1 - Initial release" -git push origin v1 --force -``` - -### Step 3: Create GitHub Release +## Workflow Hygiene -1. Go to: https://github.com/jbcom/secrets-sync/releases -2. Click "Draft a new release" -3. Select tag: `v1.0.0` -4. Release title: `v1.0.0 - GitHub Marketplace Release` -5. Release description: +- Keep `.github/workflows/*.yml` actions pinned to exact commit SHAs. +- Update the adjacent version comments when refreshing an action SHA. +- Use `gh` to verify latest stable action releases before changing pins. +- Do not grant broad workflow permissions; keep top-level `permissions: {}` and + add job-scoped permissions only where needed. -```markdown -## 🚀 Initial GitHub Marketplace Release +Current workflow action pins: -SecretSync is now available as a GitHub Action! This release provides a Docker-based action for universal secrets synchronization across multiple cloud providers. +| Action | Stable version | Commit SHA | +| --- | --- | --- | +| `actions/checkout` | `v6.0.3` | `df4cb1c069e1874edd31b4311f1884172cec0e10` | +| `actions/setup-go` | `v6.4.0` | `4a3601121dd01d1626a1e23e37211e3254c1c06c` | +| `googleapis/release-please-action` | `v5.0.0` | `45996ed1f6d02564a971a2fa1b5860e934307cf7` | +| `goreleaser/goreleaser-action` | `v7.2.2` | `5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89` | -### ✨ Features +## Publishing Flow -- 🔄 Two-phase pipeline architecture (merge → sync) -- 🎯 Support for 8+ secret stores (Vault, AWS, GCP, GitHub, Doppler, K8s, S3) -- 🌐 Multi-cloud and multi-account secret management -- 📊 GitHub-native diff annotations in PRs -- 🔒 OIDC authentication for AWS (no long-lived credentials) -- 🚀 Dynamic target discovery via AWS Organizations/Identity Center -- ⚡ Zero-configuration Docker action -- 🔐 Complete privacy - no data collection - -### 📖 Quick Start +1. Land normal feature, fix, docs, and maintenance commits using Conventional + Commit prefixes. +2. Let the release workflow open or update the release-please PR. +3. Review the release PR for correct changelog and manifest updates. +4. Merge the release PR. +5. Confirm the release workflow created a `secrets-sync-vX.Y.Z` GitHub release. +6. Confirm GoReleaser uploaded archives and `checksums.txt`. +7. Verify the action can be referenced with: ```yaml -- name: Sync Secrets - uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml - env: - VAULT_ROLE_ID: ${{ secrets.VAULT_ROLE_ID }} - VAULT_SECRET_ID: ${{ secrets.VAULT_SECRET_ID }} -``` - -### 📚 Documentation - -- [GitHub Actions Guide](./GITHUB_ACTIONS.md) -- [Quick Reference](./ACTION_QUICK_REFERENCE.md) -- [Example Workflows](../examples/github-action-workflow.yml) -- [Privacy Policy](./PRIVACY.md) -- [Support](./SUPPORT.md) - -### 🔒 Security - -SecretSync collects zero data and runs entirely within your GitHub Actions environment. See [Privacy Policy](./PRIVACY.md) for details. - -### 🤝 Contributing - -We welcome contributions! See [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines. - -### 📄 License - -MIT License - See [LICENSE](../LICENSE) ``` -6. Check "✓ Publish this Action to the GitHub Marketplace" -7. Select primary category: **Deployment** -8. Optionally add secondary categories: - - Continuous Integration - - Security -9. Click "Publish release" - -### Step 4: Verify Marketplace Listing - -1. Visit: https://github.com/marketplace/actions/secretsync -2. Verify all information displays correctly: - - Name, description, and icon - - Input parameters - - Usage examples - - Documentation links - - Author information - -3. Check that: - - README renders properly - - Examples are clear - - Links work - - Badges display - -### Step 5: Post-Publication Tasks - -1. **Update README with Marketplace badge** - ```markdown - [![GitHub Marketplace](https://img.shields.io/badge/Marketplace-SecretSync-blue.svg?colorA=24292e&colorB=0366d6&style=flat&longCache=true&logo=github)](https://github.com/marketplace/actions/secretsync) - ``` - -2. **Announce release** - - Open a tracking issue for launch feedback - - Tweet/share on social media - - Update any external documentation - -3. **Monitor feedback** - - Watch for issues - - Respond to questions - - Track usage metrics (if available) +## Marketplace Publication -4. **Set up monitoring** - - Confirm issue templates and labels are ready - - Set up issue templates - - Configure automated responses +GitHub Marketplace publication is completed from a GitHub release in the UI. +Use the release that release-please created. Do not create a parallel manual +release just to publish the Marketplace listing. -## Post-Publication Maintenance +Checklist: -### Regular Updates +- Repository is public. +- `action.yml` exists at repository root. +- `action.yml` metadata, inputs, branding, and Docker image reference are valid. +- `README.md`, `docs/GITHUB_ACTIONS.md`, and + `docs/ACTION_QUICK_REFERENCE.md` show the component tag shape. +- Security, privacy, support, contributing, and license documents are present. +- A real release exists for the tag being published. -- [ ] Monitor security vulnerabilities -- [ ] Update dependencies regularly -- [ ] Respond to issues and PRs -- [ ] Release bug fixes promptly -- [ ] Add new features based on feedback - -### Version Management - -When releasing new versions: +## Post-Release Verification ```bash -# 1. Update CHANGELOG.md -# 2. Create new version tag -git tag -a v1.1.0 -m "Release v1.1.0 - Add feature X" -git push origin v1.1.0 - -# 3. Update major version tag -git tag -fa v1 -m "Update v1 to v1.1.0" -git push origin v1 --force - -# 4. Create GitHub release with changelog +gh release view secrets-sync-vX.Y.Z --repo jbcom/secrets-sync +gh workflow run ci.yml --repo jbcom/secrets-sync ``` -### Marketplace Updates - -To update marketplace listing: - -1. Update README or action.yml as needed -2. Create new release with updated information -3. Marketplace will automatically reflect changes - -## Troubleshooting - -### Common Issues - -**Issue**: Action doesn't appear in Marketplace after publishing -- **Solution**: Check that "Publish to Marketplace" was checked during release - -**Issue**: Docker build fails for users -- **Solution**: Test multi-platform builds, ensure dependencies are available - -**Issue**: Inputs not working as expected -- **Solution**: Verify entrypoint.sh handles all inputs correctly - -**Issue**: Users report authentication errors -- **Solution**: Check documentation is clear, add troubleshooting guide - -## Support Channels - -After publishing, provide support through: - -1. **GitHub Issues**: Bug reports and feature requests -2. **GitHub Issues**: Questions and community support -3. **Email**: Security issues (private reporting) -4. **Documentation**: Keep docs updated with common questions - -## Metrics to Track - -Monitor these metrics post-publication: - -- Daily/monthly active users -- Total installations -- Issue resolution time -- PR merge rate -- Community engagement -- User feedback/ratings - -## Continuous Improvement - -Based on feedback: - -- [ ] Add requested features -- [ ] Improve documentation -- [ ] Fix reported bugs -- [ ] Optimize performance -- [ ] Enhance security - -## Checklist Summary +Also verify: -✅ All pre-publication requirements met -✅ Action tested and working -✅ Documentation complete -✅ Legal requirements satisfied -✅ Version tags created -✅ GitHub release created -✅ Marketplace listing verified -✅ Post-publication tasks completed +- Release assets are present for supported OS and architecture combinations. +- `checksums.txt` is attached. +- Marketplace examples render correctly. +- The latest documentation does not reference old monorepo package tags using + the `secretssync-v...` shape. -## Next Steps +## Manual Repairs -1. Create version tag: `git tag -a v1.0.0 -m "Initial release"` -2. Push tag: `git push origin v1.0.0` -3. Create GitHub release with Marketplace checkbox -4. Verify listing appears correctly -5. Monitor for feedback and issues +Manual tags are a repair path, not the release process. If a release workflow +fails after release-please creates a tag: ---- +1. Keep the failed tag intact while diagnosing unless the release is proven + unrecoverable. +2. Prefer rerunning the failed workflow job. +3. If a bad GitHub release was published, delete only the bad release artifacts + needed for repair. +4. Document the repair in the PR or release notes. -**Ready to publish?** Follow the steps above to make SecretSync available on the GitHub Marketplace! 🚀 +Do not create moving major aliases such as `v1` unless the repository decides +to maintain them deliberately; release-please will not update those aliases by +default. diff --git a/docs/SUPPORT.md b/docs/SUPPORT.md index 02306cb..bc33033 100644 --- a/docs/SUPPORT.md +++ b/docs/SUPPORT.md @@ -93,7 +93,7 @@ When reporting bugs, please include: # If using GitHub Action # Include the version/tag from your workflow - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z ``` 2. **Configuration** (sanitized - remove secrets!) @@ -225,17 +225,16 @@ Yes! SecretSync is free and open source (MIT License). ### Can I use this in production? -Yes! SecretSync is production-ready. Many organizations use it daily. +SecretSync is intended for production use when Vault, AWS IAM, OIDC, and +release pinning are configured for your environment. Run dry-run validation in +CI before applying changes. ### How do I upgrade? For GitHub Actions: ```yaml -# Pin to the current package release tag (recommended) -uses: jbcom/secrets-sync@secretssync-v2.0.2 - -# Pin to an exact package release tag (most stable) -uses: jbcom/secrets-sync@secretssync-v2.0.2 +# Pin to an exact package release tag +uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z # Track the branch tip (not recommended for production) uses: jbcom/secrets-sync@main diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 0b70f09..963ca7e 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -34,10 +34,11 @@ make build ## GitHub Action -Use the packaged action from this standalone repository and pin to a release tag: +Use the packaged action from this standalone repository and pin to a release +tag. Replace `X.Y.Z` with a published release version: ```yaml -- uses: jbcom/secrets-sync@secretssync-v2.0.2 +- uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml ``` diff --git a/examples/github-action-workflow.yml b/examples/github-action-workflow.yml index 5f3d841..89f780e 100644 --- a/examples/github-action-workflow.yml +++ b/examples/github-action-workflow.yml @@ -3,8 +3,8 @@ name: Sync Secrets with SecretSync # This is a complete example workflow showing how to use SecretSync # as a GitHub Action for automated secrets synchronization. # -# Pin to a package release tag for reproducible runs. -# This example uses the latest current package tag. +# Pin third-party actions to exact commits and pin SecretSync to a released +# component tag for reproducible runs. on: # Scheduled sync every 6 hours @@ -58,16 +58,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 - name: Validate Configuration (Dry Run) - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: config.yaml dry-run: 'true' @@ -87,7 +87,7 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Determine Configuration id: config @@ -99,7 +99,7 @@ jobs: fi - name: Configure AWS Credentials (OIDC) - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} aws-region: us-east-1 @@ -107,7 +107,7 @@ jobs: role-session-name: GitHubActions-SecretSync-${{ github.run_id }} - name: Run SecretSync - uses: jbcom/secrets-sync@secretssync-v2.0.2 + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z with: config: ${{ steps.config.outputs.config }} targets: ${{ github.event.inputs.targets || '' }} From bd6dbfa500e066931700a07ca1e9af57ed41e9c5 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 08:36:28 -0500 Subject: [PATCH 07/42] ci: avoid persisted checkout credentials --- .github/workflows/ci.yml | 2 ++ .github/workflows/release.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97497db..5583838 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ jobs: contents: read steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2197fa8..67f57d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,7 @@ jobs: with: ref: ${{ needs.release-please.outputs.tag_name }} fetch-depth: 0 + persist-credentials: false - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod From c07420348249b92b151ec454af26472ff86268c1 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 09:10:14 -0500 Subject: [PATCH 08/42] fix: clear go vulnerability findings --- .github/workflows/ci.yml | 1 + .github/workflows/release.yml | 1 + Dockerfile | 2 +- README.md | 3 +++ docs/PIPELINE.md | 2 +- docs/PUBLISHING_CHECKLIST.md | 1 + docs/development/contributing.md | 3 +++ docs/getting-started/installation.md | 2 +- go.mod | 8 ++++---- go.sum | 12 ++++++------ 10 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5583838..02073c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,5 +22,6 @@ jobs: with: go-version-file: go.mod cache-dependency-path: go.sum + - run: go run golang.org/x/vuln/cmd/govulncheck@v1.3.0 ./... - run: go test ./... - run: go build -o bin/secretsync ./cmd/secretsync diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67f57d3..60d545f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,6 +42,7 @@ jobs: with: go-version-file: go.mod cache-dependency-path: go.sum + - run: go run golang.org/x/vuln/cmd/govulncheck@v1.3.0 ./... - name: Run GoReleaser uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 with: diff --git a/Dockerfile b/Dockerfile index 89b2fa3..bc7c9f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # Tests now run in CI (outside Docker), so this Dockerfile focuses purely # on compiling and packaging the runtime image. ### -FROM golang:1.25-trixie AS builder +FROM golang:1.26-trixie AS builder ARG TARGETOS=linux ARG TARGETARCH=amd64 diff --git a/README.md b/README.md index c7e5585..95177dd 100644 --- a/README.md +++ b/README.md @@ -454,6 +454,9 @@ cd secrets-sync # Build go build ./... +# Vulnerability scan +go run golang.org/x/vuln/cmd/govulncheck@v1.3.0 ./... + # Unit tests go test ./... diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index 802db9e..c92e76c 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -376,7 +376,7 @@ jobs: ```yaml secrets-sync: stage: deploy - image: golang:1.25 + image: golang:1.26 before_script: - go install github.com/jbcom/secrets-sync/cmd/secretsync@latest script: diff --git a/docs/PUBLISHING_CHECKLIST.md b/docs/PUBLISHING_CHECKLIST.md index 84db35c..1f1f294 100644 --- a/docs/PUBLISHING_CHECKLIST.md +++ b/docs/PUBLISHING_CHECKLIST.md @@ -23,6 +23,7 @@ Run these before merging a release PR or manually dispatching release workflow diagnostics: ```bash +go run golang.org/x/vuln/cmd/govulncheck@v1.3.0 ./... go test ./... go build -o bin/secretsync ./cmd/secretsync goreleaser check diff --git a/docs/development/contributing.md b/docs/development/contributing.md index e28c972..f7e905d 100644 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -15,6 +15,9 @@ go mod download ## Running Tests ```bash +# Vulnerability scan +go run golang.org/x/vuln/cmd/govulncheck@v1.3.0 ./... + # Unit tests go test ./... diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 963ca7e..b2935de 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -2,7 +2,7 @@ ## Requirements -- Go 1.25+ +- Go 1.26.4+ - Docker (optional, for containerized runs or the GitHub Action image) ## Install the CLI diff --git a/go.mod b/go.mod index 423b061..d8bc1bf 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jbcom/secrets-sync -go 1.25.3 +go 1.26.4 require ( github.com/aws/aws-sdk-go-v2 v1.41.6 @@ -80,9 +80,9 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/protobuf v1.36.9 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 59e90a2..24ee62d 100644 --- a/go.sum +++ b/go.sum @@ -178,12 +178,12 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= From fc243995a19a63a23308cd9d5431f9aae4deef5b Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 09:36:36 -0500 Subject: [PATCH 09/42] fix: remove single OU discovery alias --- docs/DEPLOYMENT.md | 2 +- docs/ERROR_CONTEXT.md | 10 +++---- docs/PIPELINE.md | 3 +- docs/ROADMAP.md | 19 ++++-------- ...ganizations-discovery-integration-tests.md | 12 +++++--- examples/organizations-discovery.yaml | 24 ++++++++++----- examples/pipeline-config.yaml | 3 +- pkg/pipeline/aws_context_test.go | 6 ++-- pkg/pipeline/config_test.go | 2 +- pkg/pipeline/discovery_organizations.go | 12 ++------ pkg/pipeline/discovery_ou_test.go | 22 ++++++-------- pkg/pipeline/types.go | 29 +++++++++++++++++-- 12 files changed, 82 insertions(+), 62 deletions(-) diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index d450622..0148286 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -4,7 +4,7 @@ This guide outlines the requirements and different deployment models for the Vau ## Getting Started -The service can be configured with either a `YAML` or `JSON` configuration file, or via environment variables. The configuration is unmarshalled into the [`pipeline.Config`](../pkg/pipeline/types.go#L5) struct. An example of a fully configured `YAML` file can be found in [examples/config-full.yaml](../examples/config-full.yaml). To configure via environment variables, you must prefix the environment variable with `SECRETSYNC_` and use `_` to denote nested fields. For example, to set the `queue.type` field, you would set the environment variable `SECRETSYNC_QUEUE_TYPE`. Note: The legacy `VSS_` prefix is still supported for backwards compatibility. +The service can be configured with either a `YAML` or `JSON` configuration file, or via environment variables. The configuration is unmarshalled into the [`pipeline.Config`](../pkg/pipeline/types.go#L5) struct. An example of a fully configured `YAML` file can be found in [examples/config-full.yaml](../examples/config-full.yaml). To configure via environment variables, you must prefix the environment variable with `SECRETSYNC_` and use `_` to denote nested fields. For example, to set the `queue.type` field, you would set the environment variable `SECRETSYNC_QUEUE_TYPE`. While various examples are provided, the operator intentionally does not ship with a "default" configuration file. This is to ensure that you are aware of the security implications of each component you are enabling. This guide will walk you through each section, what it does, and how to configure it. diff --git a/docs/ERROR_CONTEXT.md b/docs/ERROR_CONTEXT.md index 17c73a9..72f6207 100644 --- a/docs/ERROR_CONTEXT.md +++ b/docs/ERROR_CONTEXT.md @@ -93,12 +93,12 @@ time="2025-12-09T17:00:05Z" level=info msg="Starting merge phase" action=Pipelin time="2025-12-09T17:00:10Z" level=info msg="Pipeline execution completed successfully" request_id=e0958539-fae2-4567-9227-592a5b36983a duration_ms=10234 ``` -## Backward Compatibility +## Error Wrapping -The enhanced error context is fully backward compatible: -- Operations without request context still work (request_id will be empty) -- Error messages maintain the same error wrapping chain -- Existing error handling code continues to work unchanged +The enhanced error context preserves the Go error wrapping chain: +- Operations without request context still work with an empty request ID. +- Error messages keep their wrapped causes available to `errors.Is` and `errors.As`. +- Callers can opt into request-scoped diagnostics without changing the underlying error type. ## Benefits diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md index c92e76c..1545afe 100644 --- a/docs/PIPELINE.md +++ b/docs/PIPELINE.md @@ -269,7 +269,8 @@ dynamic_targets: dev_accounts: discovery: organizations: - ou: "ou-xxxx-development" + ous: + - "ou-xxxx-development" recursive: true # Include accounts in child OUs imports: - dev-secrets diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 81d4a51..3cd975d 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -157,19 +157,12 @@ Based on community feedback, we're prioritizing: - **Release Candidates**: 1 week before major releases - **Early Access**: Available for enterprise partners -## Backwards Compatibility - -### Compatibility Promise -- **Configuration**: Backwards compatible within major versions -- **API**: Semantic versioning with deprecation notices -- **CLI**: Backwards compatible with deprecation warnings -- **Migration Tools**: Automated migration for breaking changes - -### Deprecation Policy -- **6 Month Notice**: Minimum 6 months notice for deprecations -- **Migration Guides**: Detailed migration documentation -- **Automated Tools**: CLI tools to assist with migrations -- **Support**: Extended support for deprecated features +## Clean Break Policy + +- **Configuration**: Prefer one current shape over compatibility aliases. +- **API**: Breaking changes are acceptable when they keep the implementation honest. +- **CLI**: Removed flags and fields should fail loudly with clear replacement guidance. +- **Migration Docs**: Document replacement configuration rather than carrying shims. ## Success Metrics diff --git a/docs/testing/organizations-discovery-integration-tests.md b/docs/testing/organizations-discovery-integration-tests.md index 4e32304..ba23eb3 100644 --- a/docs/testing/organizations-discovery-integration-tests.md +++ b/docs/testing/organizations-discovery-integration-tests.md @@ -56,7 +56,8 @@ dynamic_targets: test_ou_discovery: discovery: organizations: - ou: "ou-xxxx-development" + ous: + - "ou-xxxx-development" imports: - test-secrets ``` @@ -84,7 +85,8 @@ dynamic_targets: test_recursive_discovery: discovery: organizations: - ou: "ou-xxxx-workloads" + ous: + - "ou-xxxx-workloads" recursive: true imports: - test-secrets @@ -148,7 +150,8 @@ dynamic_targets: test_combined_filtering: discovery: organizations: - ou: "ou-xxxx-production" + ous: + - "ou-xxxx-production" tags: Environment: production imports: @@ -184,7 +187,8 @@ dynamic_targets: test_recursive_with_tags: discovery: organizations: - ou: "ou-xxxx-workloads" + ous: + - "ou-xxxx-workloads" recursive: true tags: AutoManaged: enabled diff --git a/examples/organizations-discovery.yaml b/examples/organizations-discovery.yaml index 34ec03a..a8fceff 100644 --- a/examples/organizations-discovery.yaml +++ b/examples/organizations-discovery.yaml @@ -11,7 +11,8 @@ dynamic_targets: development_accounts: discovery: organizations: - ou: "ou-xxxx-development" + ous: + - "ou-xxxx-development" imports: - shared-dev-secrets exclude: @@ -24,7 +25,8 @@ dynamic_targets: workload_accounts: discovery: organizations: - ou: "ou-xxxx-workloads" + ous: + - "ou-xxxx-workloads" recursive: true # Includes all nested OUs imports: - platform-secrets @@ -54,7 +56,8 @@ dynamic_targets: production_web_apps: discovery: organizations: - ou: "ou-xxxx-production" + ous: + - "ou-xxxx-production" tags: Workload: web-application CostCenter: engineering @@ -69,7 +72,8 @@ dynamic_targets: sandbox_environments: discovery: organizations: - ou: "ou-xxxx-sandboxes" + ous: + - "ou-xxxx-sandboxes" recursive: true # Search all child OUs too tags: AutoCleanup: enabled @@ -87,7 +91,8 @@ dynamic_targets: custom_role_accounts: discovery: organizations: - ou: "ou-xxxx-special" + ous: + - "ou-xxxx-special" imports: - special-secrets # {{.AccountID}} will be replaced with each discovered account ID @@ -127,7 +132,8 @@ dynamic_targets: dev_envs: discovery: organizations: - ou: "ou-xxxx-dev" + ous: + - "ou-xxxx-dev" recursive: true tags: AutoProvision: enabled @@ -140,7 +146,8 @@ dynamic_targets: staging_envs: discovery: organizations: - ou: "ou-xxxx-staging" + ous: + - "ou-xxxx-staging" tags: Environment: staging imports: @@ -152,7 +159,8 @@ dynamic_targets: prod_envs: discovery: organizations: - ou: "ou-xxxx-production" + ous: + - "ou-xxxx-production" tags: Environment: production Compliance: required diff --git a/examples/pipeline-config.yaml b/examples/pipeline-config.yaml index 3c93948..882c86e 100644 --- a/examples/pipeline-config.yaml +++ b/examples/pipeline-config.yaml @@ -209,7 +209,8 @@ dynamic_targets: # dev_environments: # discovery: # organizations: - # ou: "ou-xxxx-development" + # ous: + # - "ou-xxxx-development" # # Or by tags: # # tags: # # Environment: development diff --git a/pkg/pipeline/aws_context_test.go b/pkg/pipeline/aws_context_test.go index 88b7885..67e4950 100644 --- a/pkg/pipeline/aws_context_test.go +++ b/pkg/pipeline/aws_context_test.go @@ -141,13 +141,13 @@ func TestOrganizationsDiscoveryTagFiltering(t *testing.T) { // TestDiscoveryWithTagsAndOU tests discovery configuration with both OU and tags func TestDiscoveryWithTagsAndOU(t *testing.T) { cfg := &OrganizationsDiscovery{ - OU: "ou-abc-12345678", + OUs: []string{"ou-abc-12345678"}, Tags: map[string][]string{"Environment": {"production"}}, Recursive: true, } // Verify configuration is valid - assert.Equal(t, "ou-abc-12345678", cfg.OU) + assert.Equal(t, []string{"ou-abc-12345678"}, cfg.OUs) assert.True(t, cfg.Recursive) assert.NotNil(t, cfg.Tags) assert.ElementsMatch(t, []string{"production"}, cfg.Tags["Environment"]) @@ -161,7 +161,7 @@ func TestDiscoveryWithTagsOnly(t *testing.T) { // When no OU is specified, all accounts should be listed and filtered by tags // Now supports multiple values per tag for OR matching - assert.Equal(t, "", cfg.OU) + assert.Empty(t, cfg.OUs) assert.False(t, cfg.Recursive) assert.NotNil(t, cfg.Tags) assert.ElementsMatch(t, []string{"sandbox", "development"}, cfg.Tags["Environment"]) diff --git a/pkg/pipeline/config_test.go b/pkg/pipeline/config_test.go index 864d322..7aaf4b9 100644 --- a/pkg/pipeline/config_test.go +++ b/pkg/pipeline/config_test.go @@ -249,7 +249,7 @@ func TestConfigValidate(t *testing.T) { "sandboxes": { Discovery: DiscoveryConfig{ Organizations: &OrganizationsDiscovery{ - OU: "ou-xxxx-sandboxes", + OUs: []string{"ou-xxxx-sandboxes"}, Recursive: true, }, }, diff --git a/pkg/pipeline/discovery_organizations.go b/pkg/pipeline/discovery_organizations.go index a3cac34..2980788 100644 --- a/pkg/pipeline/discovery_organizations.go +++ b/pkg/pipeline/discovery_organizations.go @@ -10,7 +10,6 @@ import ( func (d *DiscoveryService) discoverFromOrganizations(cfg *OrganizationsDiscovery) ([]AccountInfo, error) { l := log.WithFields(log.Fields{ "action": "discoverFromOrganizations", - "ou": cfg.OU, "ous": cfg.OUs, "recursive": cfg.Recursive, }) @@ -22,12 +21,7 @@ func (d *DiscoveryService) discoverFromOrganizations(cfg *OrganizationsDiscovery var accounts []AccountInfo - // Collect all OUs to process (legacy single OU + new multiple OUs) - var ousToProcess []string - if cfg.OU != "" { - ousToProcess = append(ousToProcess, cfg.OU) - } - ousToProcess = append(ousToProcess, cfg.OUs...) + ousToProcess := cfg.OUs // Discover by OUs if len(ousToProcess) > 0 { @@ -59,12 +53,12 @@ func (d *DiscoveryService) discoverFromOrganizations(cfg *OrganizationsDiscovery accounts = append(accounts, allAccounts...) } - // Filter by tags if specified (legacy format) + // Filter by simple tag map if specified if len(cfg.Tags) > 0 { accounts = filterAccountsByTags(accounts, cfg.Tags) } - // Filter by enhanced tag filters if specified (v1.2.0) + // Filter by tag predicates if specified if len(cfg.TagFilters) > 0 { combination := cfg.TagCombination if combination == "" { diff --git a/pkg/pipeline/discovery_ou_test.go b/pkg/pipeline/discovery_ou_test.go index 14210a8..209d0aa 100644 --- a/pkg/pipeline/discovery_ou_test.go +++ b/pkg/pipeline/discovery_ou_test.go @@ -4,17 +4,16 @@ import ( "testing" "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func TestOrganizationsDiscovery_MultipleOUsConfig(t *testing.T) { - t.Run("legacy single OU", func(t *testing.T) { + t.Run("single OU uses OUs list", func(t *testing.T) { cfg := &OrganizationsDiscovery{ - OU: "ou-prod-123", + OUs: []string{"ou-prod-123"}, } - // Test that the configuration is properly structured - assert.Equal(t, "ou-prod-123", cfg.OU) - assert.Empty(t, cfg.OUs) + assert.Equal(t, []string{"ou-prod-123"}, cfg.OUs) }) t.Run("multiple OUs", func(t *testing.T) { @@ -22,21 +21,18 @@ func TestOrganizationsDiscovery_MultipleOUsConfig(t *testing.T) { OUs: []string{"ou-prod-123", "ou-staging-456", "ou-dev-789"}, } - assert.Empty(t, cfg.OU) assert.Len(t, cfg.OUs, 3) assert.Contains(t, cfg.OUs, "ou-prod-123") assert.Contains(t, cfg.OUs, "ou-staging-456") assert.Contains(t, cfg.OUs, "ou-dev-789") }) - t.Run("legacy OU + multiple OUs", func(t *testing.T) { - cfg := &OrganizationsDiscovery{ - OU: "ou-prod-123", - OUs: []string{"ou-staging-456", "ou-dev-789"}, - } + t.Run("removed single OU yaml is rejected", func(t *testing.T) { + cfg := &OrganizationsDiscovery{} + + err := yaml.Unmarshal([]byte("ou: ou-prod-123\n"), cfg) - assert.Equal(t, "ou-prod-123", cfg.OU) - assert.Len(t, cfg.OUs, 2) + assert.ErrorContains(t, err, "organizations.ou has been removed") }) t.Run("OU caching enabled", func(t *testing.T) { diff --git a/pkg/pipeline/types.go b/pkg/pipeline/types.go index 6d8efb8..a0c1a8f 100644 --- a/pkg/pipeline/types.go +++ b/pkg/pipeline/types.go @@ -1,6 +1,12 @@ // Package pipeline provides unified configuration and orchestration for secrets syncing pipelines. package pipeline +import ( + "fmt" + + "gopkg.in/yaml.v3" +) + // Config represents the unified pipeline configuration type Config struct { Log LogConfig `mapstructure:"log" yaml:"log"` @@ -248,19 +254,36 @@ type IdentityCenterDiscovery struct { // OrganizationsDiscovery discovers accounts from AWS Organizations type OrganizationsDiscovery struct { - OU string `mapstructure:"ou" yaml:"ou"` Tags map[string][]string `mapstructure:"tags" yaml:"tags"` Recursive bool `mapstructure:"recursive" yaml:"recursive"` NameMatching *NameMatchingConfig `mapstructure:"name_matching" yaml:"name_matching"` - // Enhanced filtering (v1.2.0) - OUs []string `mapstructure:"ous" yaml:"ous"` // Multiple OUs support + OUs []string `mapstructure:"ous" yaml:"ous"` TagFilters []TagFilter `mapstructure:"tag_filters" yaml:"tag_filters"` TagCombination string `mapstructure:"tag_combination" yaml:"tag_combination"` // "AND" or "OR", default "AND" ExcludeStatuses []string `mapstructure:"exclude_statuses" yaml:"exclude_statuses"` // e.g., ["SUSPENDED", "CLOSED"] CacheOUStructure bool `mapstructure:"cache_ou_structure" yaml:"cache_ou_structure"` // Cache OU hierarchy } +// UnmarshalYAML rejects removed single-OU configuration instead of silently ignoring it. +func (o *OrganizationsDiscovery) UnmarshalYAML(value *yaml.Node) error { + if value.Kind == yaml.MappingNode { + for i := 0; i < len(value.Content)-1; i += 2 { + if value.Content[i].Value == "ou" { + return fmt.Errorf("organizations.ou has been removed; use organizations.ous with one or more OU IDs") + } + } + } + + type organizationsDiscovery OrganizationsDiscovery + var decoded organizationsDiscovery + if err := value.Decode(&decoded); err != nil { + return err + } + *o = OrganizationsDiscovery(decoded) + return nil +} + // TagFilter represents a single tag filtering condition with wildcard support type TagFilter struct { Key string `mapstructure:"key" yaml:"key"` From 2582b83757597a710458580acfac7d1e3130de92 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 09:54:38 -0500 Subject: [PATCH 10/42] docs: remove stale compatibility shapes --- docs/MARKETPLACE.md | 2 +- docs/PYTHON_BINDINGS.md | 2 +- examples/pipeline-config.yaml | 4 ++-- pkg/diff/diff_test.go | 4 ++-- pkg/diff/versioning_test.go | 6 +++--- pkg/utils/deepmerge_test.go | 6 +++--- tests/integration/README.md | 2 +- tests/integration/fixtures/pipeline-config.yaml | 3 ++- .../{fsc_compatibility_test.go => fsc_pipeline_test.go} | 6 +++--- 9 files changed, 18 insertions(+), 17 deletions(-) rename tests/integration/{fsc_compatibility_test.go => fsc_pipeline_test.go} (98%) diff --git a/docs/MARKETPLACE.md b/docs/MARKETPLACE.md index 5524da1..2dc2941 100644 --- a/docs/MARKETPLACE.md +++ b/docs/MARKETPLACE.md @@ -150,7 +150,7 @@ They can, but documentation should recommend a component release tag because ### Should we publish a `v1` alias? Only if maintainers decide to update that alias intentionally for every -compatible release. Release-please will not maintain it automatically. +supported release. Release-please will not maintain it automatically. ### Does the Marketplace release publish binary assets? diff --git a/docs/PYTHON_BINDINGS.md b/docs/PYTHON_BINDINGS.md index a4eda20..36716db 100644 --- a/docs/PYTHON_BINDINGS.md +++ b/docs/PYTHON_BINDINGS.md @@ -235,7 +235,7 @@ Configure in your MCP client: | Mode | Relative Speed | Use Case | |------|----------------|----------| | Native bindings | 1x (fastest) | Production workloads | -| CLI subprocess | ~2-5x slower | Development, compatibility | +| CLI subprocess | ~2-5x slower | Development and local fallback | The connector automatically uses native bindings when available. diff --git a/examples/pipeline-config.yaml b/examples/pipeline-config.yaml index 882c86e..016514d 100644 --- a/examples/pipeline-config.yaml +++ b/examples/pipeline-config.yaml @@ -117,11 +117,11 @@ sources: # mount: secrets # Import existing secrets from AWS account - # legacy-secrets: + # imported-secrets: # aws: # account_id: "999999999999" # region: us-east-1 - # prefix: "/legacy/" + # prefix: "/imported/" # ============================================================================= # Merge Store diff --git a/pkg/diff/diff_test.go b/pkg/diff/diff_test.go index 66fcf8f..80739f3 100644 --- a/pkg/diff/diff_test.go +++ b/pkg/diff/diff_test.go @@ -135,14 +135,14 @@ func TestDiffSecrets_ComplexScenario(t *testing.T) { "api-keys/stripe": map[string]interface{}{"KEY": "sk_xxx"}, "api-keys/datadog": map[string]interface{}{"API_KEY": "dd_xxx"}, "database/postgres": map[string]interface{}{"HOST": "old.db.com", "PASSWORD": "old"}, - "legacy/config": map[string]interface{}{"OLD": "value"}, + "retired/config": map[string]interface{}{"OLD": "value"}, } desired := map[string]interface{}{ "api-keys/stripe": map[string]interface{}{"KEY": "sk_xxx"}, // unchanged "api-keys/datadog": map[string]interface{}{"API_KEY": "dd_yyy"}, // modified "database/postgres": map[string]interface{}{"HOST": "new.db.com", "PASSWORD": "new"}, // modified "api-keys/newrelic": map[string]interface{}{"KEY": "nr_xxx"}, // added - // legacy/config removed + // retired/config removed } changes := DiffSecrets(current, desired) diff --git a/pkg/diff/versioning_test.go b/pkg/diff/versioning_test.go index ed6cc29..c93f5fd 100644 --- a/pkg/diff/versioning_test.go +++ b/pkg/diff/versioning_test.go @@ -153,8 +153,8 @@ func TestFormatDiffWithVersions(t *testing.T) { assert.Contains(t, output, "(was v5)", "Should show version for removed secret") } -// TestBackwardCompatibility tests that diff works without version information (v1.2.0 - Requirement 24) -func TestBackwardCompatibility(t *testing.T) { +// TestDiffWithoutVersionMetadata tests the current no-version diff path. +func TestDiffWithoutVersionMetadata(t *testing.T) { current := map[string]interface{}{ "app/api-key": map[string]interface{}{"key": "old-value"}, } @@ -162,7 +162,7 @@ func TestBackwardCompatibility(t *testing.T) { "app/api-key": map[string]interface{}{"key": "new-value"}, } - // Test without version information (backward compatibility) + // Test without version information. changes := DiffSecrets(current, desired) assert.Len(t, changes, 1) assert.Equal(t, ChangeTypeModified, changes[0].ChangeType) diff --git a/pkg/utils/deepmerge_test.go b/pkg/utils/deepmerge_test.go index 1da2c3e..8f5d669 100644 --- a/pkg/utils/deepmerge_test.go +++ b/pkg/utils/deepmerge_test.go @@ -374,8 +374,8 @@ func TestDeepMerge_MultipleImports(t *testing.T) { } } -// TestDeepMerge_FSCCompatibility tests specific FSC use cases for FlipsideCrypto compatibility -func TestDeepMerge_FSCCompatibility(t *testing.T) { +// TestDeepMerge_FSCUseCases tests specific FSC deep-merge use cases. +func TestDeepMerge_FSCUseCases(t *testing.T) { t.Run("3+ level deep nesting", func(t *testing.T) { // FSC has deeply nested config structures dst := map[string]interface{}{ @@ -553,7 +553,7 @@ func TestDeepMerge_FSCCompatibility(t *testing.T) { } }) - t.Run("JSON round-trip compatibility", func(t *testing.T) { + t.Run("JSON round trip", func(t *testing.T) { // Verify that merging works correctly through JSON serialization dstJSON := []byte(`{ "api_keys": {"stripe": "sk_test_123"}, diff --git a/tests/integration/README.md b/tests/integration/README.md index 30e4149..1ccbc1c 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -112,7 +112,7 @@ The GitHub Actions CI workflow uses the docker-compose stack for integration tes - Syncs to AWS Secrets Manager - Validates final output -2. **fsc_compatibility_test.go** - FlipsideCrypto compatibility +2. **fsc_pipeline_test.go** - FSC pipeline shape - Multi-tier target inheritance (Staging → Production → Demo) - AWS Organizations account discovery - Fuzzy account name matching diff --git a/tests/integration/fixtures/pipeline-config.yaml b/tests/integration/fixtures/pipeline-config.yaml index 63b5808..410407c 100644 --- a/tests/integration/fixtures/pipeline-config.yaml +++ b/tests/integration/fixtures/pipeline-config.yaml @@ -68,7 +68,8 @@ dynamic_targets: dev_accounts: discovery: organizations: - ou: "ou-xxxx-development" + ous: + - "ou-xxxx-development" recursive: true # Fuzzy match account names to target configs name_matching: diff --git a/tests/integration/fsc_compatibility_test.go b/tests/integration/fsc_pipeline_test.go similarity index 98% rename from tests/integration/fsc_compatibility_test.go rename to tests/integration/fsc_pipeline_test.go index 3fd551c..c7bebd3 100644 --- a/tests/integration/fsc_compatibility_test.go +++ b/tests/integration/fsc_pipeline_test.go @@ -1,4 +1,4 @@ -// Package integration provides FSC-compatible end-to-end tests. +// Package integration provides FSC pipeline-shape end-to-end tests. // These tests validate the complete pipeline with realistic patterns: // - Multi-tier target inheritance (Staging → Production → Demo) // - Deepmerge strategies (list append, dict merge, scalar override) @@ -46,8 +46,8 @@ type AccountData struct { } `json:"organizational_units"` } -// TestFSCCompatibilityFullPipeline validates the complete FSC-compatible workflow -func TestFSCCompatibilityFullPipeline(t *testing.T) { +// TestFSCPipelineFullFlow validates the complete FSC-style workflow. +func TestFSCPipelineFullFlow(t *testing.T) { skipIfNoIntegrationEnv(t) ctx := context.Background() From a542296b9fbef87e7dbbee67acada826a4d5d57f Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 09:56:13 -0500 Subject: [PATCH 11/42] test: guard removed organizations ou shape --- pkg/pipeline/discovery_ou_test.go | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/pkg/pipeline/discovery_ou_test.go b/pkg/pipeline/discovery_ou_test.go index 209d0aa..3a9814c 100644 --- a/pkg/pipeline/discovery_ou_test.go +++ b/pkg/pipeline/discovery_ou_test.go @@ -1,6 +1,8 @@ package pipeline import ( + "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -44,6 +46,24 @@ func TestOrganizationsDiscovery_MultipleOUsConfig(t *testing.T) { }) } +func TestRepositoryExamplesRejectRemovedOrganizationsOUShape(t *testing.T) { + paths := []string{ + filepath.Join("..", "..", "examples", "pipeline-config.yaml"), + filepath.Join("..", "..", "tests", "integration", "fixtures", "pipeline-config.yaml"), + } + + for _, path := range paths { + t.Run(path, func(t *testing.T) { + data, err := os.ReadFile(path) + assert.NoError(t, err) + + var doc yaml.Node + assert.NoError(t, yaml.Unmarshal(data, &doc)) + assert.False(t, hasRemovedOrganizationsOUShape(&doc), "%s uses removed organizations.ou", path) + }) + } +} + func TestDiscoveryService_CacheInitialization(t *testing.T) { discovery := &DiscoveryService{ ouCache: make(map[string][]AccountInfo), @@ -68,3 +88,43 @@ func TestDiscoveryService_CacheInitialization(t *testing.T) { assert.Len(t, cached, 1) assert.Equal(t, "111111111111", cached[0].ID) } + +func hasRemovedOrganizationsOUShape(node *yaml.Node) bool { + if node == nil { + return false + } + + if node.Kind == yaml.MappingNode { + for i := 0; i < len(node.Content)-1; i += 2 { + key := node.Content[i] + value := node.Content[i+1] + if key.Value == "organizations" && mappingNodeHasKey(value, "ou") { + return true + } + if hasRemovedOrganizationsOUShape(value) { + return true + } + } + return false + } + + for _, child := range node.Content { + if hasRemovedOrganizationsOUShape(child) { + return true + } + } + return false +} + +func mappingNodeHasKey(node *yaml.Node, keyName string) bool { + if node == nil || node.Kind != yaml.MappingNode { + return false + } + + for i := 0; i < len(node.Content)-1; i += 2 { + if node.Content[i].Value == keyName { + return true + } + } + return false +} From 54622888f89ea539484fb7e54d93c3bb18cb58ee Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 10:37:35 -0500 Subject: [PATCH 12/42] test: enforce workflow action sha pins --- workflow_pinning_test.go | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 workflow_pinning_test.go diff --git a/workflow_pinning_test.go b/workflow_pinning_test.go new file mode 100644 index 0000000..94335b1 --- /dev/null +++ b/workflow_pinning_test.go @@ -0,0 +1,69 @@ +package secretsync_test + +import ( + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "testing" +) + +var ( + actionRefPattern = regexp.MustCompile(`^\s*(?:-\s*)?uses:\s*([^#\s]+)`) + pinnedSHAPattern = regexp.MustCompile(`^[0-9a-f]{40}$`) +) + +func TestWorkflowActionsArePinnedToExactSHAs(t *testing.T) { + workflowRoot := filepath.Join(".github", "workflows") + entries, err := os.ReadDir(workflowRoot) + if err != nil { + t.Fatalf("read workflow directory: %v", err) + } + + var offenders []string + for _, entry := range entries { + if entry.IsDir() { + continue + } + name := entry.Name() + if !strings.HasSuffix(name, ".yml") && !strings.HasSuffix(name, ".yaml") { + continue + } + + path := filepath.Join(workflowRoot, name) + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read workflow %s: %v", path, err) + } + + for index, line := range strings.Split(string(content), "\n") { + matches := actionRefPattern.FindStringSubmatch(line) + if matches == nil { + continue + } + + uses := strings.TrimSpace(matches[1]) + if strings.HasPrefix(uses, "./") || strings.HasPrefix(uses, "docker://") { + continue + } + + parts := strings.Split(uses, "@") + ref := "" + if len(parts) == 2 { + ref = parts[1] + } + if !pinnedSHAPattern.MatchString(ref) { + offenders = append(offenders, path+":"+itoa(index+1)+": "+uses) + } + } + } + + if len(offenders) > 0 { + t.Fatalf("workflow actions must be pinned to exact commit SHAs:\n%s", strings.Join(offenders, "\n")) + } +} + +func itoa(value int) string { + return strconv.Itoa(value) +} From fe231ac0708104e3c8d2641448a3c953885c606e Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 11:28:22 -0500 Subject: [PATCH 13/42] fix: avoid raw client and secret logs --- pkg/client/aws/aws.go | 8 +++++++- pkg/client/aws/aws_test.go | 7 +++++++ pkg/client/vault/vault.go | 30 +++++++++++++----------------- pkg/client/vault/vault_test.go | 16 ++++++++++++++++ 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/pkg/client/aws/aws.go b/pkg/client/aws/aws.go index e8d214e..7953452 100644 --- a/pkg/client/aws/aws.go +++ b/pkg/client/aws/aws.go @@ -159,7 +159,13 @@ func NewClient(cfg *AwsClient) (*AwsClient, error) { breakerName := fmt.Sprintf("aws-secretsmanager-%s-%s", vc.Name, vc.Region) vc.breaker = circuitbreaker.New(circuitbreaker.DefaultConfig(breakerName)) - l.Debugf("client=%+v", vc) + l.WithFields(log.Fields{ + "name": vc.Name, + "region": vc.Region, + "roleArn": vc.RoleArn, + "cacheTTL": vc.CacheTTL, + "hasKmsKey": vc.EncryptionKey != "", + }).Debug("client initialized") l.Trace("end") return vc, nil } diff --git a/pkg/client/aws/aws_test.go b/pkg/client/aws/aws_test.go index 274e835..e2024b6 100644 --- a/pkg/client/aws/aws_test.go +++ b/pkg/client/aws/aws_test.go @@ -110,6 +110,13 @@ func TestAwsClient_Validate(t *testing.T) { } } +func TestAwsClient_DoesNotLogRawClientStruct(t *testing.T) { + content, err := os.ReadFile("aws.go") + require.NoError(t, err) + + assert.NotContains(t, string(content), `Debugf("client=%+v"`) +} + func TestAwsClient_Driver(t *testing.T) { client := &AwsClient{} assert.Equal(t, driver.DriverNameAws, client.Driver()) diff --git a/pkg/client/vault/vault.go b/pkg/client/vault/vault.go index d307cac..400d51a 100644 --- a/pkg/client/vault/vault.go +++ b/pkg/client/vault/vault.go @@ -124,7 +124,13 @@ func NewClient(cfg *VaultClient) (*VaultClient, error) { breakerName := fmt.Sprintf("vault-%s", vc.Address) vc.breaker = circuitbreaker.New(circuitbreaker.DefaultConfig(breakerName)) - l.Tracef("client=%+v", vc) + l.WithFields(log.Fields{ + "address": vc.Address, + "path": vc.Path, + "authMethod": vc.AuthMethod, + "namespace": vc.Namespace, + "merge": vc.Merge, + }).Trace("client initialized") l.Trace("end") return vc, nil } @@ -279,21 +285,14 @@ func (vc *VaultClient) GetKVSecretOnce(ctx context.Context, s string) (map[strin observability.RecordDuration(observability.VaultAPICallDuration, startTime, "get_secret", status) }() - l := log.WithFields(log.Fields{ - "address": vc.Address, - "role": vc.Role, - "path": s, - "method": vc.AuthMethod, - }) - var secrets map[string]interface{} if s == "" { observability.RecordError(observability.VaultErrors, "get_secret", "invalid_path") - return secrets, errors.New("secret path required") + return nil, errors.New("secret path required") } ss := strings.Split(s, "/") if len(ss) < 2 { observability.RecordError(observability.VaultErrors, "get_secret", "invalid_path") - return secrets, errors.New("secret path must be in kv/path/to/secret format") + return nil, errors.New("secret path must be in kv/path/to/secret format") } ss = insertSliceString(ss, 1, "data") //log.Debugf("headers_sent=%+v", vc.Client.Headers()) @@ -301,7 +300,7 @@ func (vc *VaultClient) GetKVSecretOnce(ctx context.Context, s string) (map[strin s = strings.Join(ss, "/") if c == nil { observability.RecordError(observability.VaultErrors, "get_secret", "not_initialized") - return secrets, errors.New("vault client not initialized") + return nil, errors.New("vault client not initialized") } // Ensure circuit breaker is initialized @@ -313,7 +312,7 @@ func (vc *VaultClient) GetKVSecretOnce(ctx context.Context, s string) (map[strin }) if err != nil { observability.RecordError(observability.VaultErrors, "get_secret", "api_error") - return secrets, circuitbreaker.WrapError(err, vc.breaker.Name(), vc.breaker.State()) + return nil, circuitbreaker.WrapError(err, vc.breaker.Name(), vc.breaker.State()) } secret := result @@ -321,7 +320,6 @@ func (vc *VaultClient) GetKVSecretOnce(ctx context.Context, s string) (map[strin observability.RecordError(observability.VaultErrors, "get_secret", "not_found") return nil, errors.New("secret not found: " + s) } - l.Tracef("secret=%+v", secret) if secret.Data["data"] == nil { observability.RecordError(observability.VaultErrors, "get_secret", "no_data") return nil, errors.New("secret data not found: " + s) @@ -386,7 +384,6 @@ func (vc *VaultClient) WriteSecret(ctx context.Context, meta metav1.ObjectMeta, if err != nil { return nil, err } - var secrets map[string]interface{} if vc.Merge { sec, getErr := vc.GetSecret(ctx, s) if getErr != nil { @@ -419,18 +416,17 @@ func (vc *VaultClient) WriteSecret(ctx context.Context, meta metav1.ObjectMeta, if terr != nil { return nil, terr } - secrets, err = vc.WriteSecretWithLatestCAS(ctx, s, data) + _, err = vc.WriteSecretWithLatestCAS(ctx, s, data) if err != nil { terr := vc.NewToken(ctx) if terr != nil { return nil, terr } - secrets, err = vc.WriteSecretWithLatestCAS(ctx, s, data) + _, err = vc.WriteSecretWithLatestCAS(ctx, s, data) if err != nil { return nil, err } } - l.Tracef("secrets=%+v", secrets) return nil, err } diff --git a/pkg/client/vault/vault_test.go b/pkg/client/vault/vault_test.go index e169cab..794e2ef 100644 --- a/pkg/client/vault/vault_test.go +++ b/pkg/client/vault/vault_test.go @@ -3,6 +3,7 @@ package vault import ( "context" "encoding/json" + "os" "strings" "testing" @@ -118,6 +119,21 @@ func TestVaultClient_Driver(t *testing.T) { assert.Equal(t, driver.DriverNameVault, client.Driver()) } +func TestVaultClient_DoesNotLogRawSecretPayloads(t *testing.T) { + content, err := os.ReadFile("vault.go") + require.NoError(t, err) + + source := string(content) + forbidden := []string{ + `Tracef("secret=%+v"`, + `Tracef("secrets=%+v"`, + `Tracef("client=%+v"`, + } + for _, pattern := range forbidden { + assert.NotContains(t, source, pattern) + } +} + func TestVaultClient_GetPath(t *testing.T) { client := &VaultClient{Path: "secret/data/test"} assert.Equal(t, "secret/data/test", client.GetPath()) From 5bee28bd7197142a5e51e03b5f84b1ba39a5d724 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 11:39:48 -0500 Subject: [PATCH 14/42] fix: lock pipeline error exit precedence --- Dockerfile | 2 +- cmd/secretsync/cmd/pipeline.go | 16 ++++++++---- cmd/secretsync/cmd/pipeline_test.go | 38 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc7c9f8..2117af8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # Tests now run in CI (outside Docker), so this Dockerfile focuses purely # on compiling and packaging the runtime image. ### -FROM golang:1.26-trixie AS builder +FROM golang:1.26.4-trixie AS builder ARG TARGETOS=linux ARG TARGETARCH=amd64 diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index 85f9925..0e04a18 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -194,13 +194,12 @@ func runPipeline(cmd *cobra.Command, args []string) error { // Determine exit behavior hasErrors := pipelineHadErrors(err, results) if exitCodeMode { - if hasErrors { - cancel() - os.Exit(2) + diffExitCode := 0 + if !hasErrors { + diffExitCode = p.ExitCode() } - exitCode := p.ExitCode() + exitCode := pipelineExitCode(hasErrors, diffExitCode) if exitCode != 0 { - cancel() os.Exit(exitCode) } return nil @@ -233,6 +232,13 @@ func pipelineHadErrors(err error, results []pipeline.Result) bool { return false } +func pipelineExitCode(hasErrors bool, diffExitCode int) int { + if hasErrors { + return 2 + } + return diffExitCode +} + // parseOutputFormat converts string to OutputFormat func parseOutputFormat(s string) diff.OutputFormat { switch strings.ToLower(s) { diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go index 993e931..cb75155 100644 --- a/cmd/secretsync/cmd/pipeline_test.go +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -165,3 +165,41 @@ func TestPipelineHadErrors(t *testing.T) { }) } } + +func TestPipelineExitCode(t *testing.T) { + tests := map[string]struct { + hasErrors bool + diffExitCode int + want int + }{ + "pipeline errors exit as execution errors": { + hasErrors: true, + diffExitCode: 0, + want: 2, + }, + "execution errors win over changed diff": { + hasErrors: true, + diffExitCode: 1, + want: 2, + }, + "changed diff preserves diff exit code": { + diffExitCode: 1, + want: 1, + }, + "diff errors preserve diff error exit code": { + diffExitCode: 2, + want: 2, + }, + "clean run exits zero": { + want: 0, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + if got := pipelineExitCode(tc.hasErrors, tc.diffExitCode); got != tc.want { + t.Fatalf("pipelineExitCode() = %d, want %d", got, tc.want) + } + }) + } +} From 032516d1b0d63a227728ae5e392e3361219c569c Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 11:56:24 -0500 Subject: [PATCH 15/42] docs: document logging safety contract --- docs/OBSERVABILITY.md | 19 +++++++++++++++++++ docs/SECURITY.md | 17 ++++++++++++++++- docs_security_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 docs_security_test.go diff --git a/docs/OBSERVABILITY.md b/docs/OBSERVABILITY.md index 8d488c9..d560cba 100644 --- a/docs/OBSERVABILITY.md +++ b/docs/OBSERVABILITY.md @@ -63,6 +63,25 @@ Once enabled, metrics are exposed at: - **Metrics**: `http://localhost:9090/metrics` - **Health check**: `http://localhost:9090/health` +## Logging Safety + +Logs and metrics are designed for operational visibility without exposing the +secret bytes being synchronized. SecretSync records request IDs, operation +names, durations, counts, paths, targets, account identifiers, and provider +error context. It must not log raw secret values, raw Vault secret payloads, raw +AWS secret payloads, or raw client structures. + +Use JSON logs when shipping to a centralized platform: + +```bash +secretsync pipeline --config config.yaml --log-format json --log-level info +``` + +Debug and trace logging can reveal more operational metadata and should be sent +only to secured sinks with appropriate retention. If a provider returns +credentials in an error string, treat that upstream behavior as a provider or +configuration issue and rotate the exposed credential. + ## Available Metrics ### Vault Metrics diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 28895ee..ea1a2e0 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -8,6 +8,21 @@ As this service is effectively an event bus for your various secret stores and t The service is designed to be secure by default, preferrring more explicit configuration as opposed to insecure defaults. This does mean initial set up will not be one-liner fire-and-forget. That is intentional, as it forces you to think about the security implications of the decisions you are making rather than starting up the process insecurely, forgetting about it, and then being surprised when something goes wrong. If started with no configuration and no command line flags, the service will exit with an error. All components of the service default to disabled, you must explicitly enable the components you wish to use. +### Logging and Diagnostics + +SecretSync logs operational metadata for troubleshooting, not secret material. +Vault and AWS client initialization logs are limited to explicit non-secret +fields such as address, path, auth method, region, role ARN, cache settings, and +boolean capability flags. Raw secret values, raw Vault secret response objects, +raw AWS secret response objects, and raw client structures must not be written +to logs at any level. + +Diagnostics may include secret paths, target names, account IDs, error classes, +request IDs, durations, counts, and operation names. Treat those logs as +operationally sensitive, but they should not contain the bytes being synced. +Keep `--log-level debug` and `--log-level trace` restricted to trusted +operators and secured log sinks. + ### Segregation of Duties By default, all components of the app default to disabled. This is to ensure that you are only enabling the components you need. To run in "single binary mode", you must explicitly enable each component. This is to ensure that you are aware of the security implications of each component you are enabling. This also enables you to more easily deploy the service in a microservices architecture, where you can run the webhook service in one container and the sync operator in another. @@ -148,4 +163,4 @@ If you are running in a Kubernetes cluster, you can use the Kubernetes auth meth ## Vulnerability Reporting -If you believe you have found a security vulnerability in this project, please report it privately to the project maintainers. If you are unsure whether the issue is a security vulnerability, please report it anyway. We take all reports seriously and will respond promptly to your inquiry. Please do not disclose the issue publicly until we have had a chance to address it. You can report a security vulnerability by emailing [robert@lestak.sh](mailto:robert@lestak.sh). Please include the word "SECURITY" in the subject line. \ No newline at end of file +If you believe you have found a security vulnerability in this project, please report it privately to the project maintainers. If you are unsure whether the issue is a security vulnerability, please report it anyway. We take all reports seriously and will respond promptly to your inquiry. Please do not disclose the issue publicly until we have had a chance to address it. You can report a security vulnerability by emailing [robert@lestak.sh](mailto:robert@lestak.sh). Please include the word "SECURITY" in the subject line. diff --git a/docs_security_test.go b/docs_security_test.go new file mode 100644 index 0000000..fb8df2a --- /dev/null +++ b/docs_security_test.go @@ -0,0 +1,30 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" +) + +func TestSecurityDocsDocumentLoggingContract(t *testing.T) { + required := []string{ + "raw secret values", + "raw Vault secret", + "raw AWS secret", + "raw client structures", + } + + for _, path := range []string{"docs/SECURITY.md", "docs/OBSERVABILITY.md"} { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := strings.ToLower(strings.Join(strings.Fields(string(content)), " ")) + for _, phrase := range required { + if !strings.Contains(text, strings.ToLower(phrase)) { + t.Fatalf("%s must document logging contract phrase %q", path, phrase) + } + } + } +} From e4fff3a119cb075e34b6a0d05cb84e21bbcb573a Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:18:05 -0500 Subject: [PATCH 16/42] refactor: remove vss compatibility alias --- Dockerfile | 2 -- cmd/secretsync/cmd/context.go | 4 +-- cmd/secretsync/cmd/graph.go | 4 +-- cmd/secretsync/cmd/help_text_test.go | 31 +++++++++++++++++ cmd/secretsync/cmd/migrate.go | 18 +++++----- cmd/secretsync/cmd/validate.go | 4 +-- dockerfile_test.go | 34 +++++++++++++++++++ ...ganizations-discovery-integration-tests.md | 14 ++++---- 8 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 cmd/secretsync/cmd/help_text_test.go create mode 100644 dockerfile_test.go diff --git a/Dockerfile b/Dockerfile index 2117af8..534623b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,8 +59,6 @@ WORKDIR /app RUN mkdir -p /etc/ssl/certs COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /out/secretsync /usr/local/bin/secretsync -# Keep vss as a symlink for backwards compatibility -RUN ln -s /usr/local/bin/secretsync /usr/local/bin/vss # Default command - Viper reads SECRETSYNC_* env vars directly ENTRYPOINT ["/usr/local/bin/secretsync"] diff --git a/cmd/secretsync/cmd/context.go b/cmd/secretsync/cmd/context.go index 66a20e5..6d1ae90 100644 --- a/cmd/secretsync/cmd/context.go +++ b/cmd/secretsync/cmd/context.go @@ -25,8 +25,8 @@ This shows: Understanding your execution context is critical for multi-account operations. Examples: - vss context - vss context --config config.yaml`, + secretsync context + secretsync context --config config.yaml`, RunE: runContext, } diff --git a/cmd/secretsync/cmd/graph.go b/cmd/secretsync/cmd/graph.go index d132f32..6e7c9dd 100644 --- a/cmd/secretsync/cmd/graph.go +++ b/cmd/secretsync/cmd/graph.go @@ -21,8 +21,8 @@ The graph shows: - Execution order (by dependency level) Examples: - vss graph --config config.yaml - vss graph --config config.yaml --format dot`, + secretsync graph --config config.yaml + secretsync graph --config config.yaml --format dot`, RunE: runGraph, } diff --git a/cmd/secretsync/cmd/help_text_test.go b/cmd/secretsync/cmd/help_text_test.go new file mode 100644 index 0000000..416db18 --- /dev/null +++ b/cmd/secretsync/cmd/help_text_test.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "strings" + "testing" +) + +func TestCommandHelpDoesNotAdvertiseVSSAlias(t *testing.T) { + commands := []*cobraCommandText{ + {name: "context", long: contextCmd.Long}, + {name: "graph", long: graphCmd.Long}, + {name: "migrate", long: migrateCmd.Long}, + {name: "validate", long: validateCmd.Long}, + } + + for _, command := range commands { + t.Run(command.name, func(t *testing.T) { + if strings.Contains(command.long, "vss ") || strings.Contains(command.long, "./vss") { + t.Fatalf("%s help should advertise secretsync, not vss:\n%s", command.name, command.long) + } + if !strings.Contains(command.long, "secretsync ") { + t.Fatalf("%s help should include secretsync examples:\n%s", command.name, command.long) + } + }) + } +} + +type cobraCommandText struct { + name string + long string +} diff --git a/cmd/secretsync/cmd/migrate.go b/cmd/secretsync/cmd/migrate.go index edd9fc5..5167bce 100644 --- a/cmd/secretsync/cmd/migrate.go +++ b/cmd/secretsync/cmd/migrate.go @@ -24,17 +24,17 @@ var ( var migrateCmd = &cobra.Command{ Use: "migrate", Short: "Migrate from other secret management tools", - Long: `Migrate configuration from other secret management tools to vss pipeline format. + Long: `Migrate configuration from other secret management tools to SecretSync pipeline format. Supported sources: - terraform-secretsmanager: Terraform-based AWS Secrets Manager pipeline Example: - vss migrate --from terraform-secretsmanager \ - --targets config/targets.yaml \ - --secrets config/secrets.yaml \ - --accounts config/accounts.yaml \ - --output config.yaml`, + secretsync migrate --from terraform-secretsmanager \ + --targets config/targets.yaml \ + --secrets config/secrets.yaml \ + --accounts config/accounts.yaml \ + --output config.yaml`, RunE: runMigrate, } @@ -214,7 +214,7 @@ func migrateTerraformSecretManager() error { // Add header comment header := `# Pipeline configuration migrated from terraform-aws-secretsmanager -# Generated by: vss migrate --from terraform-secretsmanager +# Generated by: secretsync migrate --from terraform-secretsmanager # # Review and adjust as needed: # - Verify Vault address and authentication @@ -236,8 +236,8 @@ func migrateTerraformSecretManager() error { fmt.Println("Next steps:") fmt.Printf(" 1. Review the generated config: %s\n", outputFile) fmt.Println(" 2. Add Vault authentication (token, approle, etc.)") - fmt.Println(" 3. Validate: vss validate --config " + outputFile) - fmt.Println(" 4. Dry run: vss pipeline --config " + outputFile + " --dry-run") + fmt.Println(" 3. Validate: secretsync validate --config " + outputFile) + fmt.Println(" 4. Dry run: secretsync pipeline --config " + outputFile + " --dry-run") return nil } diff --git a/cmd/secretsync/cmd/validate.go b/cmd/secretsync/cmd/validate.go index 519e7c3..b23378b 100644 --- a/cmd/secretsync/cmd/validate.go +++ b/cmd/secretsync/cmd/validate.go @@ -22,8 +22,8 @@ Checks: - AWS execution context (optional) Examples: - vss validate --config config.yaml - vss validate --config config.yaml --check-aws`, + secretsync validate --config config.yaml + secretsync validate --config config.yaml --check-aws`, RunE: runValidate, } diff --git a/dockerfile_test.go b/dockerfile_test.go new file mode 100644 index 0000000..194d7c5 --- /dev/null +++ b/dockerfile_test.go @@ -0,0 +1,34 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" +) + +func TestDockerfileDoesNotShipVSSAlias(t *testing.T) { + content, err := os.ReadFile("Dockerfile") + if err != nil { + t.Fatalf("read Dockerfile: %v", err) + } + + text := string(content) + for _, forbidden := range []string{"/usr/local/bin/vss", "backwards compatibility", "backward compatibility"} { + if strings.Contains(text, forbidden) { + t.Fatalf("Dockerfile should not ship vss compatibility alias %q", forbidden) + } + } +} + +func TestOrganizationsTestingDocsDoNotAdvertiseVSSAlias(t *testing.T) { + path := "docs/testing/organizations-discovery-integration-tests.md" + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + if strings.Contains(text, "./vss") || strings.Contains(text, " vss ") { + t.Fatalf("%s should advertise secretsync, not vss", path) + } +} diff --git a/docs/testing/organizations-discovery-integration-tests.md b/docs/testing/organizations-discovery-integration-tests.md index ba23eb3..cd50ff4 100644 --- a/docs/testing/organizations-discovery-integration-tests.md +++ b/docs/testing/organizations-discovery-integration-tests.md @@ -71,7 +71,7 @@ dynamic_targets: **Validation:** ```bash # Run the pipeline in dry-run mode -./vss pipeline --config test-config.yaml --dry-run +secretsync pipeline --config test-config.yaml --dry-run # Verify discovered targets in output # Should show accounts directly in the OU only @@ -106,7 +106,7 @@ aws organizations list-organizational-units-for-parent --parent-id ou-xxxx-workl # Then check each child OU # Compare with discovery output -./vss pipeline --config test-config.yaml --dry-run | grep "Discovered target" +secretsync pipeline --config test-config.yaml --dry-run | grep "Discovered target" ``` ### Test 3: Tag-Based Filtering (All Accounts) @@ -139,7 +139,7 @@ for account in $(aws organizations list-accounts --query 'Accounts[].Id' --outpu done # Compare with discovery output -./vss pipeline --config test-config.yaml --dry-run +secretsync pipeline --config test-config.yaml --dry-run ``` ### Test 4: Combined OU and Tag Filtering @@ -176,7 +176,7 @@ for account in $(aws organizations list-accounts-for-parent --parent-id ou-xxxx- done # Run discovery -./vss pipeline --config test-config.yaml --dry-run +secretsync pipeline --config test-config.yaml --dry-run ``` ### Test 5: Recursive OU with Tag Filtering @@ -206,7 +206,7 @@ dynamic_targets: ```bash # This requires checking all accounts in the OU hierarchy # and verifying they have the required tags -./vss pipeline --config test-config.yaml --dry-run --log-level debug +secretsync pipeline --config test-config.yaml --dry-run --log-level debug ``` ### Test 6: Account Name Resolution @@ -231,7 +231,7 @@ dynamic_targets: **Validation:** ```bash # Check that discovered targets have meaningful names -./vss pipeline --config test-config.yaml --dry-run | grep "Discovered target" +secretsync pipeline --config test-config.yaml --dry-run | grep "Discovered target" # Names should be sanitized: # "Analytics Sandbox" → "Analytics_Sandbox" @@ -260,7 +260,7 @@ dynamic_targets: ### Enable Debug Logging ```bash -./vss pipeline --config config.yaml --dry-run --log-level debug +secretsync pipeline --config config.yaml --dry-run --log-level debug ``` ### Common Issues From 0cee5d045a98e3b3311d708306eceaedb58c3c3d Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:28:21 -0500 Subject: [PATCH 17/42] refactor: align helm crd with secretsync api --- ...retsync.extendeddata.dev_secretsyncs.yaml} | 22 +++---- .../templates/clusterrole.yaml | 10 ++-- docs/USAGE.md | 6 +- helm_chart_test.go | 58 +++++++++++++++++++ 4 files changed, 77 insertions(+), 19 deletions(-) rename deploy/charts/secretsync/charts/secretsync-operator/crds/{vaultsecretsync.lestak.sh_vaultsecretsyncs.yaml => secretsync.extendeddata.dev_secretsyncs.yaml} (95%) create mode 100644 helm_chart_test.go diff --git a/deploy/charts/secretsync/charts/secretsync-operator/crds/vaultsecretsync.lestak.sh_vaultsecretsyncs.yaml b/deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml similarity index 95% rename from deploy/charts/secretsync/charts/secretsync-operator/crds/vaultsecretsync.lestak.sh_vaultsecretsyncs.yaml rename to deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml index 2134ed6..3b484cf 100644 --- a/deploy/charts/secretsync/charts/secretsync-operator/crds/vaultsecretsync.lestak.sh_vaultsecretsyncs.yaml +++ b/deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml @@ -4,20 +4,20 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - name: vaultsecretsyncs.vaultsecretsync.lestak.sh + name: secretsyncs.secretsync.extendeddata.dev spec: - group: vaultsecretsync.lestak.sh + group: secretsync.extendeddata.dev names: - kind: VaultSecretSync - listKind: VaultSecretSyncList - plural: vaultsecretsyncs + kind: SecretSync + listKind: SecretSyncList + plural: secretsyncs shortNames: - - vss - singular: vaultsecretsync + - ss + singular: secretsync scope: Namespaced versions: - additionalPrinterColumns: - - description: Current status of the VaultSecretSync + - description: Current status of the SecretSync jsonPath: .status.status name: Status type: string @@ -28,7 +28,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: VaultSecretSync is the Schema for the vaultsecretsyncs API + description: SecretSync is the Schema for the secretsyncs API properties: apiVersion: description: |- @@ -48,7 +48,7 @@ spec: metadata: type: object spec: - description: VaultSecretSyncSpec defines the desired state of VaultSecretSync + description: SecretSyncSpec defines the desired state of SecretSync properties: dest: items: @@ -309,7 +309,7 @@ spec: - source type: object status: - description: VaultSecretSyncStatus defines the observed state of VaultSecretSync + description: SecretSyncStatus defines the observed state of SecretSync properties: hash: type: string diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml index 4b28b8c..16e4aa4 100644 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml +++ b/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml @@ -12,10 +12,10 @@ rules: - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - - apiGroups: ["vaultsecretsync.lestak.sh"] - resources: ["vaultsecretsyncs"] + - apiGroups: ["secretsync.extendeddata.dev"] + resources: ["secretsyncs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - - apiGroups: ["vaultsecretsync.lestak.sh"] - resources: ["vaultsecretsyncs/status"] + - apiGroups: ["secretsync.extendeddata.dev"] + resources: ["secretsyncs/status"] verbs: ["get", "update", "patch"] -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/docs/USAGE.md b/docs/USAGE.md index 72dfb23..43932bc 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -281,17 +281,17 @@ EOF Once created, the operator will begin syncing secrets from the source to the destination. You can trigger an immediate sync by annotating the `SecretSync` resource with `force-sync`. ```bash -kubectl annotate vaultsecretsync example force-sync=$(date +%s) --overwrite +kubectl annotate secretsync example force-sync=$(date +%s) --overwrite ``` To sync all `SecretSync` resources in a namespace, you can use the following command: ```bash -kubectl get vaultsecretsync -n example -o name | xargs -I {} kubectl annotate -n example {} force-sync=$(date +%s) --overwrite +kubectl get secretsyncs -n example -o name | xargs -I {} kubectl annotate -n example {} force-sync=$(date +%s) --overwrite ``` To sync all `SecretSync` resources in all namespaces, you can use the following command: ```bash -for ns in $(kubectl get ns -o name | cut -d/ -f2); do kubectl get vaultsecretsync -n $ns -o name | xargs -I {} kubectl annotate -n $ns {} force-sync=$(date +%s) --overwrite; done +for ns in $(kubectl get ns -o name | cut -d/ -f2); do kubectl get secretsyncs -n $ns -o name | xargs -I {} kubectl annotate -n $ns {} force-sync=$(date +%s) --overwrite; done ``` diff --git a/helm_chart_test.go b/helm_chart_test.go new file mode 100644 index 0000000..d5516ce --- /dev/null +++ b/helm_chart_test.go @@ -0,0 +1,58 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" +) + +func TestHelmChartUsesSecretSyncAPI(t *testing.T) { + paths := []string{ + "deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml", + "deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml", + "docs/USAGE.md", + } + + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + for _, forbidden := range []string{ + "vaultsecretsync.lestak.sh", + "VaultSecretSync", + "vaultsecretsync", + " vss", + "- vss", + } { + if strings.Contains(text, forbidden) { + t.Fatalf("%s should not preserve old VaultSecretSync API surface %q", path, forbidden) + } + } + } +} + +func TestHelmCRDMatchesGoAPIGroup(t *testing.T) { + crdPath := "deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml" + content, err := os.ReadFile(crdPath) + if err != nil { + t.Fatalf("read %s: %v", crdPath, err) + } + + text := string(content) + for _, required := range []string{ + "name: secretsyncs.secretsync.extendeddata.dev", + "group: secretsync.extendeddata.dev", + "kind: SecretSync", + "listKind: SecretSyncList", + "plural: secretsyncs", + "- ss", + "singular: secretsync", + } { + if !strings.Contains(text, required) { + t.Fatalf("%s missing required SecretSync CRD field %q", crdPath, required) + } + } +} From ff210d7279f90286ef9d618ad6c2192feab38a33 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:40:36 -0500 Subject: [PATCH 18/42] docs: remove fork-era security and migration residue --- dockerfile_test.go | 11 +++++++ docs/SECURITY.md | 8 ++++- docs_security_test.go | 24 ++++++++++++++ scripts/break-fork.sh | 75 ------------------------------------------- 4 files changed, 42 insertions(+), 76 deletions(-) delete mode 100755 scripts/break-fork.sh diff --git a/dockerfile_test.go b/dockerfile_test.go index 194d7c5..811d9ec 100644 --- a/dockerfile_test.go +++ b/dockerfile_test.go @@ -32,3 +32,14 @@ func TestOrganizationsTestingDocsDoNotAdvertiseVSSAlias(t *testing.T) { t.Fatalf("%s should advertise secretsync, not vss", path) } } + +func TestForkBreakScriptIsNotShipped(t *testing.T) { + path := "scripts/break-fork.sh" + _, err := os.Stat(path) + if err == nil { + t.Fatalf("%s should not ship in the independent repository", path) + } + if !os.IsNotExist(err) { + t.Fatalf("stat %s: %v", path, err) + } +} diff --git a/docs/SECURITY.md b/docs/SECURITY.md index ea1a2e0..73f052b 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -163,4 +163,10 @@ If you are running in a Kubernetes cluster, you can use the Kubernetes auth meth ## Vulnerability Reporting -If you believe you have found a security vulnerability in this project, please report it privately to the project maintainers. If you are unsure whether the issue is a security vulnerability, please report it anyway. We take all reports seriously and will respond promptly to your inquiry. Please do not disclose the issue publicly until we have had a chance to address it. You can report a security vulnerability by emailing [robert@lestak.sh](mailto:robert@lestak.sh). Please include the word "SECURITY" in the subject line. +If you believe you have found a security vulnerability in this project, please +report it privately through +[GitHub Security Advisories](https://github.com/jbcom/secrets-sync/security/advisories) +or email [security@jbcom.dev](mailto:security@jbcom.dev). If you are unsure +whether the issue is a security vulnerability, please report it anyway. We take +all reports seriously and will respond promptly to your inquiry. Please do not +disclose the issue publicly until we have had a chance to address it. diff --git a/docs_security_test.go b/docs_security_test.go index fb8df2a..ec0c162 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -28,3 +28,27 @@ func TestSecurityDocsDocumentLoggingContract(t *testing.T) { } } } + +func TestSecurityDocsUseProjectReportingContacts(t *testing.T) { + required := []string{ + "https://github.com/jbcom/secrets-sync/security/advisories", + "security@jbcom.dev", + } + + for _, path := range []string{"SECURITY.md", "docs/SECURITY.md"} { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + if strings.Contains(text, "robert@lestak.sh") { + t.Fatalf("%s should not use the old fork-era security contact", path) + } + for _, phrase := range required { + if !strings.Contains(text, phrase) { + t.Fatalf("%s must document reporting contact %q", path, phrase) + } + } + } +} diff --git a/scripts/break-fork.sh b/scripts/break-fork.sh deleted file mode 100755 index 4e2c732..0000000 --- a/scripts/break-fork.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# break-fork.sh - Script to break the fork and rename to secretsync -# -# Usage: ./scripts/break-fork.sh [new-org] [new-repo] -# Example: ./scripts/break-fork.sh jbcom secretsync - -set -euo pipefail - -NEW_ORG="${1:-jbcom}" -NEW_REPO="${2:-secretsync}" -OLD_MODULE="github.com/robertlestak/vault-secret-sync" -NEW_MODULE="github.com/${NEW_ORG}/${NEW_REPO}" - -echo "=== Breaking Fork: vault-secret-sync → ${NEW_REPO} ===" -echo "" -echo "Old module: ${OLD_MODULE}" -echo "New module: ${NEW_MODULE}" -echo "" - -# Confirm -read -p "Continue? (y/N) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Aborted." - exit 1 -fi - -echo "" -echo "Step 1: Updating go.mod..." -sed -i "s|module ${OLD_MODULE}|module ${NEW_MODULE}|g" go.mod - -echo "Step 2: Updating all Go imports..." -find . -name "*.go" -type f -exec sed -i "s|${OLD_MODULE}|${NEW_MODULE}|g" {} + - -echo "Step 3: Updating documentation..." -find . -name "*.md" -type f -exec sed -i "s|${OLD_MODULE}|${NEW_MODULE}|g" {} + -find . -name "*.md" -type f -exec sed -i "s|vault-secret-sync|${NEW_REPO}|g" {} + - -echo "Step 4: Updating Helm charts..." -find deploy/charts -name "*.yaml" -type f -exec sed -i "s|vault-secret-sync|${NEW_REPO}|g" {} + -find deploy/charts -name "Chart.yaml" -type f -exec sed -i "s|vault-secret-sync|${NEW_REPO}|g" {} + - -echo "Step 5: Updating Dockerfile..." -sed -i "s|vault-secret-sync|${NEW_REPO}|g" Dockerfile - -echo "Step 6: Updating GitHub workflows..." -find .github -name "*.yml" -type f -exec sed -i "s|vault-secret-sync|${NEW_REPO}|g" {} + - -echo "Step 7: Running go mod tidy..." -go mod tidy - -echo "Step 8: Verifying build..." -go build ./... - -echo "" -echo "=== Fork Break Complete ===" -echo "" -echo "Next steps:" -echo "1. Create new GitHub repo: https://github.com/${NEW_ORG}/${NEW_REPO}" -echo " - Do NOT create as a fork" -echo " - Create empty (no README, no .gitignore)" -echo "" -echo "2. Remove old git history and push fresh:" -echo " rm -rf .git" -echo " git init" -echo " git add -A" -echo " git commit -m 'Initial commit: ${NEW_REPO} - Universal Secrets Sync'" -echo " git remote add origin https://github.com/${NEW_ORG}/${NEW_REPO}.git" -echo " git push -u origin main" -echo "" -echo "3. (Optional) Archive old repo with redirect notice" -echo "" -echo "4. Update Docker Hub / container registry" -echo "" -echo "5. Update Helm chart repository" From 3d48d1c4b75cca85d2dcbf62eaf9f4dd07bec117 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:41:49 -0500 Subject: [PATCH 19/42] docs: align security support with current major --- SECURITY.md | 6 ++---- docs_security_test.go | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 219f64b..8f96dd6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,10 +6,8 @@ We actively support the following versions of SecretSync with security updates: | Version | Supported | | ------- | ------------------ | -| 1.2.x | ✅ Yes | -| 1.1.x | ✅ Yes | -| 1.0.x | ⚠️ Critical fixes only | -| < 1.0 | ❌ No | +| 2.x | ✅ Yes | +| < 2.0 | ❌ No | ## Reporting a Vulnerability diff --git a/docs_security_test.go b/docs_security_test.go index ec0c162..0f92ef4 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -52,3 +52,20 @@ func TestSecurityDocsUseProjectReportingContacts(t *testing.T) { } } } + +func TestSecurityPolicyDocumentsCurrentMajorOnly(t *testing.T) { + content, err := os.ReadFile("SECURITY.md") + if err != nil { + t.Fatalf("read SECURITY.md: %v", err) + } + + text := string(content) + if !strings.Contains(text, "| 2.x") { + t.Fatalf("SECURITY.md should document current 2.x support") + } + for _, oldVersion := range []string{"| 1.2.x", "| 1.1.x", "| 1.0.x"} { + if strings.Contains(text, oldVersion) { + t.Fatalf("SECURITY.md should not advertise old support line %q", oldVersion) + } + } +} From 15dff279b4ada512c6b1aef8e2f343cd2b304373 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:43:24 -0500 Subject: [PATCH 20/42] docs: align roadmap with current major --- docs/FAQ.md | 2 +- docs/ROADMAP.md | 13 +++++++------ docs_version_test.go | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 docs_version_test.go diff --git a/docs/FAQ.md b/docs/FAQ.md index c7335d0..0e827fe 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -19,7 +19,7 @@ SecretSync is an enterprise-grade secret synchronization pipeline that automates ### Is SecretSync production-ready? -Yes! SecretSync v1.2.0 is production-ready with: +Yes. The current SecretSync 2.x line is production-ready with: - 150+ comprehensive tests - Full CI/CD pipeline with integration tests - Circuit breakers and error handling diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 3cd975d..7b562d5 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -2,13 +2,14 @@ This roadmap outlines the planned development direction for SecretSync. It's a living document that evolves based on community feedback and changing requirements. -## Current Status: v1.2.0 (December 2025) +## Current Status: v2.x -✅ **Production Ready** - All core features implemented and battle-tested +✅ **Production Ready** - The current 2.x line is the supported release line for +the independent SecretSync repository. ## Upcoming Releases -### v1.3.0 - Observability & Integrations (Q1 2026) +### v2.1.0 - Observability & Integrations **Theme**: Enhanced monitoring and ecosystem integrations @@ -36,7 +37,7 @@ This roadmap outlines the planned development direction for SecretSync. It's a l - **Configuration Templates**: Pre-built templates for common patterns - **IDE Extensions**: VS Code extension for configuration editing -### v1.4.0 - Enterprise Features (Q2 2026) +### v2.2.0 - Enterprise Features **Theme**: Advanced enterprise capabilities and governance @@ -64,7 +65,7 @@ This roadmap outlines the planned development direction for SecretSync. It's a l - **Batch Operations**: Bulk secret operations for efficiency - **Rate Limiting**: Intelligent rate limiting and backoff -### v1.5.0 - Ecosystem & Platform (Q3 2026) +### v2.3.0 - Ecosystem & Platform **Theme**: Platform features and ecosystem growth @@ -92,7 +93,7 @@ This roadmap outlines the planned development direction for SecretSync. It's a l - **Shell Integration**: Bash/Zsh completion and integration - **Configuration Management**: CLI-based configuration management -## Future Considerations (v2.0+) +## Future Considerations (v3.0+) ### Major Architecture Evolution diff --git a/docs_version_test.go b/docs_version_test.go new file mode 100644 index 0000000..8301496 --- /dev/null +++ b/docs_version_test.go @@ -0,0 +1,36 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" +) + +func TestDocsDoNotAdvertiseOldCurrentVersion(t *testing.T) { + forbiddenByPath := map[string][]string{ + "docs/ROADMAP.md": { + "Current Status: v1.2.0", + "Future Considerations (v2.0+)", + "### v1.3.0", + "### v1.4.0", + "### v1.5.0", + }, + "docs/FAQ.md": { + "SecretSync v1.2.0 is production-ready", + }, + } + + for path, forbidden := range forbiddenByPath { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + for _, phrase := range forbidden { + if strings.Contains(text, phrase) { + t.Fatalf("%s should not advertise old current-version phrase %q", path, phrase) + } + } + } +} From e233f75a18e1d10794caa4959b45a51b5f7974e9 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 12:44:46 -0500 Subject: [PATCH 21/42] docs: remove stale roadmap version phrase --- docs/ROADMAP.md | 2 +- docs_version_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 7b562d5..8881b7c 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -130,7 +130,7 @@ Based on community feedback, we're prioritizing: - **GitHub Issues**: Share your use cases and requirements - **Feature Requests**: Create detailed feature requests with business justification - **User Surveys**: Participate in periodic user surveys -- **Community Calls**: Join monthly community calls (coming in v1.3.0) +- **Community Calls**: Join monthly community calls when scheduled ### 🤝 Contributions - **Code Contributions**: Implement features you need diff --git a/docs_version_test.go b/docs_version_test.go index 8301496..8b69025 100644 --- a/docs_version_test.go +++ b/docs_version_test.go @@ -14,6 +14,7 @@ func TestDocsDoNotAdvertiseOldCurrentVersion(t *testing.T) { "### v1.3.0", "### v1.4.0", "### v1.5.0", + "coming in v1.3.0", }, "docs/FAQ.md": { "SecretSync v1.2.0 is production-ready", From 052f9ca80bcaf187e64772cef93af61725e8dbff Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 14:20:24 -0500 Subject: [PATCH 22/42] test: guard release note product casing --- .goreleaser.yml | 2 +- release_config_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 release_config_test.go diff --git a/.goreleaser.yml b/.goreleaser.yml index c5a7701..5c5ee8e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -94,7 +94,7 @@ release: prerelease: auto mode: replace header: | - ## secretsync {{ .Tag }} + ## SecretSync {{ .Tag }} ### Installation diff --git a/release_config_test.go b/release_config_test.go new file mode 100644 index 0000000..6490f22 --- /dev/null +++ b/release_config_test.go @@ -0,0 +1,25 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" +) + +func TestGoReleaserUsesProductNameInReleaseNotes(t *testing.T) { + content, err := os.ReadFile(".goreleaser.yml") + if err != nil { + t.Fatalf("read .goreleaser.yml: %v", err) + } + + text := string(content) + if !strings.Contains(text, "project_name: secretsync") { + t.Fatalf(".goreleaser.yml should keep lowercase secretsync artifact naming") + } + if !strings.Contains(text, "## SecretSync {{ .Tag }}") { + t.Fatalf(".goreleaser.yml should use SecretSync product casing in release notes") + } + if strings.Contains(text, "## secretsync {{ .Tag }}") { + t.Fatalf(".goreleaser.yml should not use lowercase product name in release notes") + } +} From 3a124b80b960863a05908afee96d3b58dfddce71 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 14:34:03 -0500 Subject: [PATCH 23/42] fix: address secrets sync review hygiene --- SECURITY.md | 2 +- dockerfile_test.go | 6 ++++-- docs_security_test.go | 8 ++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 8f96dd6..bf899d8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -111,7 +111,7 @@ We follow responsible disclosure practices: Security updates are released as: -- **Patch releases** for supported versions (e.g., 1.2.1 → 1.2.2) +- **Patch releases** for supported versions (e.g., 2.0.1 → 2.0.2) - **Security advisories** published on GitHub - **Release notes** highlighting security fixes diff --git a/dockerfile_test.go b/dockerfile_test.go index 811d9ec..09410f3 100644 --- a/dockerfile_test.go +++ b/dockerfile_test.go @@ -2,6 +2,7 @@ package secretsync_test import ( "os" + "regexp" "strings" "testing" ) @@ -27,8 +28,9 @@ func TestOrganizationsTestingDocsDoNotAdvertiseVSSAlias(t *testing.T) { t.Fatalf("read %s: %v", path, err) } - text := string(content) - if strings.Contains(text, "./vss") || strings.Contains(text, " vss ") { + text := strings.ToLower(strings.Join(strings.Fields(string(content)), " ")) + vssToken := regexp.MustCompile(`\bvss\b`) + if strings.Contains(text, "./vss") || vssToken.MatchString(text) { t.Fatalf("%s should advertise secretsync, not vss", path) } } diff --git a/docs_security_test.go b/docs_security_test.go index 0f92ef4..f6d5728 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -68,4 +68,12 @@ func TestSecurityPolicyDocumentsCurrentMajorOnly(t *testing.T) { t.Fatalf("SECURITY.md should not advertise old support line %q", oldVersion) } } + for _, oldExample := range []string{"1.2.1", "1.2.2"} { + if strings.Contains(text, oldExample) { + t.Fatalf("SECURITY.md should not use unsupported 1.x patch example %q", oldExample) + } + } + if !strings.Contains(text, "2.0.1") || !strings.Contains(text, "2.0.2") { + t.Fatalf("SECURITY.md should use a supported 2.x patch-release example") + } } From 1b1c8d5b59e47046f4f6953862d81b2d068a7418 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 14:50:18 -0500 Subject: [PATCH 24/42] docs: remove stale v1 feature labels --- README.md | 28 ++++++++++++++-------------- docs/FAQ.md | 4 ++-- docs/GETTING_STARTED.md | 8 ++++---- docs_version_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 95177dd..9ccfc3a 100644 --- a/README.md +++ b/README.md @@ -39,24 +39,24 @@ SecretSync is an independent [jbcom/secrets-sync](https://github.com/jbcom/secre ## ✨ Key Features -### 🔍 **Advanced Discovery** (v1.2.0) +### 🔍 **Advanced Discovery** - **AWS Organizations Integration**: Discover accounts with tag filtering, wildcards, and OU-based selection - **AWS Identity Center**: Permission set discovery and account assignment mapping - **Smart Caching**: Multi-level caching for optimal performance at scale -### 📚 **Secret Versioning** (v1.2.0) +### 📚 **Secret Versioning** - **Complete Audit Trail**: Track every secret change with metadata - **S3-Based Storage**: Reliable, scalable version history - **Rollback Capability**: CLI support for version rollback - **Retention Policies**: Configurable cleanup of old versions -### 🎨 **Enhanced Diff Output** (v1.2.0) +### 🎨 **Enhanced Diff Output** - **Side-by-Side Comparison**: Visual diff with aligned columns and color coding - **Intelligent Masking**: Automatic detection and masking of sensitive values - **Multiple Formats**: Human, JSON, GitHub Actions, and compact outputs - **Rich Statistics**: Detailed change counts, sizes, and timing -### 🛡️ **Enterprise Reliability** (v1.1.0) +### 🛡️ **Enterprise Reliability** - **Circuit Breakers**: Automatic failure detection and recovery - **Prometheus Metrics**: Production-ready observability with `/metrics` endpoint - **Request Tracking**: Unique request IDs and duration tracking @@ -199,16 +199,16 @@ crewai_tools = get_tools("crewai") # Validate configuration secretsync validate --config pipeline.yaml -# Dry run with enhanced diff output (v1.2.0) +# Dry run with enhanced diff output secretsync pipeline --config pipeline.yaml --dry-run --output side-by-side -# Full pipeline execution with metrics (v1.1.0) +# Full pipeline execution with metrics secretsync pipeline --config pipeline.yaml --metrics-port 9090 # CI/CD mode (exit codes: 0=no changes, 1=changes, 2=errors) secretsync pipeline --config pipeline.yaml --dry-run --exit-code -# Version management (v1.2.0) +# Version management secretsync versions --secret-path "app/database/password" secretsync sync --version 5 --target production ``` @@ -216,7 +216,7 @@ secretsync sync --version 5 --target production ### Example Configuration ```yaml -# pipeline.yaml - v1.2.0 with advanced features +# pipeline.yaml - advanced features vault: address: "https://vault.example.com" namespace: "admin" @@ -225,7 +225,7 @@ aws: region: "us-east-1" execution_role_pattern: "arn:aws:iam::{account_id}:role/SecretsSync" -# Advanced discovery (v1.2.0) +# Advanced discovery discovery: aws_organizations: enabled: true @@ -246,13 +246,13 @@ discovery: region: "us-east-1" cache_ttl: "30m" -# Secret versioning (v1.2.0) +# Secret versioning versioning: enabled: true s3_bucket: "company-secretsync-versions" retention_days: 90 -# Observability (v1.1.0) +# Observability observability: metrics: enabled: true @@ -327,17 +327,17 @@ See [GitHub Actions documentation](./docs/GITHUB_ACTIONS.md) for complete usage secretsync pipeline --config pipeline.yaml ``` -### Output Formats (Enhanced in v1.2.0) +### Output Formats | Format | Use Case | Features | |--------|----------|----------| | `human` | Interactive terminal output | Color coding, readable layout | -| `side-by-side` | **NEW** Visual comparison | Aligned columns, intelligent masking | +| `side-by-side` | Visual comparison | Aligned columns, intelligent masking | | `json` | Machine parsing, logging | Structured data with metadata | | `github` | GitHub Actions annotations | PR comments, file annotations | | `compact` | One-line CI status | Minimal output for scripts | -**Value Masking (v1.2.0)**: Sensitive values are automatically masked by default. Use `--show-values` flag to display actual values (use with caution in CI/CD). +**Value Masking**: Sensitive values are automatically masked by default. Use `--show-values` flag to display actual values (use with caution in CI/CD). ## 📚 Documentation diff --git a/docs/FAQ.md b/docs/FAQ.md index 0e827fe..eadcf67 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -158,9 +158,9 @@ targets: ## Features -### What's new in v1.2.0? +### What's included in the current feature set? -Major new features: +Major features: - **Enhanced AWS Organizations Discovery** with tag filtering and wildcards - **AWS Identity Center Integration** for permission set discovery - **Secret Versioning System** with S3-based storage and rollback diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 1d78894..8d0da55 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -150,7 +150,7 @@ aws secretsmanager list-secrets --query 'SecretList[?starts_with(Name, `myapp/`) ### Enable Advanced Features -#### 1. Add Observability (v1.1.0) +#### 1. Add Observability ```bash # Run with metrics endpoint @@ -161,7 +161,7 @@ curl http://localhost:9090/metrics curl http://localhost:9090/health ``` -#### 2. Enhanced Diff Output (v1.2.0) +#### 2. Enhanced Diff Output ```bash # Side-by-side comparison @@ -175,7 +175,7 @@ JSON output is a stable pipeline result envelope with success status, aggregate secret counts, per-phase `results`, and nested `diff`/`diff_output` fields when diff computation is enabled. -#### 3. Secret Versioning (v1.2.0) +#### 3. Secret Versioning Add to your config: ```yaml @@ -185,7 +185,7 @@ versioning: retention_days: 90 ``` -#### 4. AWS Organizations Discovery (v1.2.0) +#### 4. AWS Organizations Discovery ```yaml discovery: diff --git a/docs_version_test.go b/docs_version_test.go index 8b69025..2d86f05 100644 --- a/docs_version_test.go +++ b/docs_version_test.go @@ -1,7 +1,9 @@ package secretsync_test import ( + "io/fs" "os" + "path/filepath" "strings" "testing" ) @@ -35,3 +37,40 @@ func TestDocsDoNotAdvertiseOldCurrentVersion(t *testing.T) { } } } + +func TestPublicDocsDoNotAdvertiseOldFeatureReleaseLabels(t *testing.T) { + forbidden := []string{"v1.1.0", "v1.2.0"} + paths := []string{"README.md"} + + if err := filepath.WalkDir("docs", func(path string, entry fs.DirEntry, err error) error { + if err != nil { + return err + } + if entry.IsDir() || filepath.Ext(path) != ".md" { + return nil + } + paths = append(paths, path) + return nil + }); err != nil { + t.Fatalf("walk docs: %v", err) + } + + var offenders []string + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + for _, phrase := range forbidden { + if strings.Contains(text, phrase) { + offenders = append(offenders, path+": "+phrase) + } + } + } + + if len(offenders) > 0 { + t.Fatalf("public docs should not advertise old feature-release labels:\n%s", strings.Join(offenders, "\n")) + } +} From 1ab251d2cd21da3c3daf4172a71f788bc02dc7f9 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 14:52:14 -0500 Subject: [PATCH 25/42] test: guard action input docs --- action_docs_test.go | 174 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 action_docs_test.go diff --git a/action_docs_test.go b/action_docs_test.go new file mode 100644 index 0000000..e751a23 --- /dev/null +++ b/action_docs_test.go @@ -0,0 +1,174 @@ +package secretsync_test + +import ( + "os" + "strings" + "testing" + + "gopkg.in/yaml.v3" +) + +type actionMetadata struct { + Inputs map[string]actionInput `yaml:"inputs"` +} + +type actionInput struct { + Default string `yaml:"default"` +} + +func TestActionInputDocsMatchMetadata(t *testing.T) { + actionInputs := readActionInputDefaults(t) + + for _, doc := range []struct { + path string + heading string + }{ + {"docs/GITHUB_ACTIONS.md", "## Input Parameters"}, + {"docs/ACTION_QUICK_REFERENCE.md", "## All Inputs"}, + } { + docInputs := readDocumentedInputDefaults(t, doc.path, doc.heading) + if diff := compareInputDefaults(actionInputs, docInputs); len(diff) > 0 { + t.Fatalf("%s action input table must match action.yml:\n%s", doc.path, strings.Join(diff, "\n")) + } + } +} + +func readActionInputDefaults(t *testing.T) map[string]string { + t.Helper() + + content, err := os.ReadFile("action.yml") + if err != nil { + t.Fatalf("read action.yml: %v", err) + } + + var metadata actionMetadata + if err := yaml.Unmarshal(content, &metadata); err != nil { + t.Fatalf("parse action.yml: %v", err) + } + + inputs := make(map[string]string, len(metadata.Inputs)) + for name, input := range metadata.Inputs { + inputs[name] = input.Default + } + return inputs +} + +func readDocumentedInputDefaults(t *testing.T, path string, heading string) map[string]string { + t.Helper() + + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + lines := strings.Split(string(content), "\n") + inSection := false + inputColumn := -1 + defaultColumn := -1 + inputs := map[string]string{} + + for _, line := range lines { + trimmed := strings.TrimSpace(line) + if trimmed == heading { + inSection = true + continue + } + if !inSection { + continue + } + if strings.HasPrefix(trimmed, "## ") { + break + } + if !strings.HasPrefix(trimmed, "|") { + continue + } + + cells := splitMarkdownTableRow(trimmed) + if len(cells) == 0 || isMarkdownSeparatorRow(cells) { + continue + } + if inputColumn == -1 || defaultColumn == -1 { + for index, cell := range cells { + switch strings.ToLower(strings.TrimSpace(cell)) { + case "input": + inputColumn = index + case "default": + defaultColumn = index + } + } + continue + } + if len(cells) <= inputColumn || len(cells) <= defaultColumn { + continue + } + + inputName := trimMarkdownCode(cells[inputColumn]) + if inputName == "" { + continue + } + inputs[inputName] = normalizeDefaultCell(cells[defaultColumn]) + } + + if len(inputs) == 0 { + t.Fatalf("%s has no action input table under %q", path, heading) + } + return inputs +} + +func splitMarkdownTableRow(row string) []string { + trimmed := strings.Trim(row, "|") + parts := strings.Split(trimmed, "|") + for index, part := range parts { + parts[index] = strings.TrimSpace(part) + } + return parts +} + +func isMarkdownSeparatorRow(cells []string) bool { + for _, cell := range cells { + if strings.Trim(cell, "-: ") != "" { + return false + } + } + return true +} + +func trimMarkdownCode(value string) string { + return strings.Trim(strings.TrimSpace(value), "`") +} + +func normalizeDefaultCell(value string) string { + defaultValue := strings.TrimSpace(value) + if strings.HasPrefix(defaultValue, "`") { + withoutOpeningTick := strings.TrimPrefix(defaultValue, "`") + if codeSpan, _, ok := strings.Cut(withoutOpeningTick, "`"); ok { + defaultValue = codeSpan + } + } else { + defaultValue = trimMarkdownCode(defaultValue) + } + if before, _, ok := strings.Cut(defaultValue, " "); ok { + defaultValue = before + } + return strings.Trim(defaultValue, `"`) +} + +func compareInputDefaults(want map[string]string, got map[string]string) []string { + var diff []string + for name, defaultValue := range want { + documented, ok := got[name] + if !ok { + diff = append(diff, "missing input: "+name) + continue + } + if documented != defaultValue { + diff = append(diff, name+": documented default "+documented+" != action default "+defaultValue) + } + } + for name := range got { + if _, ok := want[name]; !ok { + diff = append(diff, "extra input: "+name) + } + } + return diff +} From 42f74458a1acdb89bd56095f9b95cd1157e4d310 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 15:05:52 -0500 Subject: [PATCH 26/42] test: guard workflow pin documentation --- workflow_pinning_test.go | 89 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/workflow_pinning_test.go b/workflow_pinning_test.go index 94335b1..7db0434 100644 --- a/workflow_pinning_test.go +++ b/workflow_pinning_test.go @@ -10,17 +10,60 @@ import ( ) var ( - actionRefPattern = regexp.MustCompile(`^\s*(?:-\s*)?uses:\s*([^#\s]+)`) - pinnedSHAPattern = regexp.MustCompile(`^[0-9a-f]{40}$`) + actionRefPattern = regexp.MustCompile(`^\s*(?:-\s*)?uses:\s*([^#\s]+)(?:\s+#\s*(\S+))?`) + actionVersionCommentPattern = regexp.MustCompile(`^v\d+\.\d+\.\d+$`) + pinnedSHAPattern = regexp.MustCompile(`^[0-9a-f]{40}$`) + publishingChecklistPinPattern = regexp.MustCompile("^\\|\\s*`([^`]+)`\\s*\\|\\s*`([^`]+)`\\s*\\|\\s*`([0-9a-f]{40})`\\s*\\|$") ) +type workflowActionPin struct { + Version string + SHA string +} + func TestWorkflowActionsArePinnedToExactSHAs(t *testing.T) { + pins := workflowActionPins(t) + if len(pins) == 0 { + t.Fatalf("expected workflow action pins") + } +} + +func TestPublishingChecklistMatchesWorkflowActionPins(t *testing.T) { + workflowPins := workflowActionPins(t) + checklistPins := publishingChecklistPins(t) + + if len(checklistPins) == 0 { + t.Fatalf("docs/PUBLISHING_CHECKLIST.md must list current workflow action pins") + } + if len(workflowPins) != len(checklistPins) { + t.Fatalf("publishing checklist pin count mismatch: workflow=%d checklist=%d", len(workflowPins), len(checklistPins)) + } + for action, workflowPin := range workflowPins { + checklistPin, ok := checklistPins[action] + if !ok { + t.Fatalf("docs/PUBLISHING_CHECKLIST.md missing workflow action %s", action) + } + if checklistPin != workflowPin { + t.Fatalf("docs/PUBLISHING_CHECKLIST.md pin for %s = %+v, want %+v", action, checklistPin, workflowPin) + } + } + for action := range checklistPins { + if _, ok := workflowPins[action]; !ok { + t.Fatalf("docs/PUBLISHING_CHECKLIST.md lists non-workflow action %s", action) + } + } +} + +func workflowActionPins(t *testing.T) map[string]workflowActionPin { + t.Helper() + workflowRoot := filepath.Join(".github", "workflows") entries, err := os.ReadDir(workflowRoot) if err != nil { t.Fatalf("read workflow directory: %v", err) } + pins := map[string]workflowActionPin{} var offenders []string for _, entry := range entries { if entry.IsDir() { @@ -48,20 +91,52 @@ func TestWorkflowActionsArePinnedToExactSHAs(t *testing.T) { continue } - parts := strings.Split(uses, "@") - ref := "" - if len(parts) == 2 { - ref = parts[1] + action, ref, found := strings.Cut(uses, "@") + version := "" + if len(matches) > 2 { + version = matches[2] } - if !pinnedSHAPattern.MatchString(ref) { + if !found || !pinnedSHAPattern.MatchString(ref) { offenders = append(offenders, path+":"+itoa(index+1)+": "+uses) + continue + } + if !actionVersionCommentPattern.MatchString(version) { + offenders = append(offenders, path+":"+itoa(index+1)+": missing stable version comment for "+uses) + continue + } + + pin := workflowActionPin{Version: version, SHA: ref} + if existing, ok := pins[action]; ok && existing != pin { + offenders = append(offenders, path+":"+itoa(index+1)+": conflicting pin for "+action) + continue } + pins[action] = pin } } if len(offenders) > 0 { t.Fatalf("workflow actions must be pinned to exact commit SHAs:\n%s", strings.Join(offenders, "\n")) } + return pins +} + +func publishingChecklistPins(t *testing.T) map[string]workflowActionPin { + t.Helper() + + content, err := os.ReadFile(filepath.Join("docs", "PUBLISHING_CHECKLIST.md")) + if err != nil { + t.Fatalf("read publishing checklist: %v", err) + } + + pins := map[string]workflowActionPin{} + for _, line := range strings.Split(string(content), "\n") { + matches := publishingChecklistPinPattern.FindStringSubmatch(strings.TrimSpace(line)) + if matches == nil { + continue + } + pins[matches[1]] = workflowActionPin{Version: matches[2], SHA: matches[3]} + } + return pins } func itoa(value int) string { From 9cdd0471d7de76c30ba7986a89a3293ebf0ba7b0 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 15:15:05 -0500 Subject: [PATCH 27/42] docs: remove fork-era usage examples --- docs/USAGE.md | 10 +++++----- docs/architecture/HLA-microservice.drawio | 2 +- docs_security_test.go | 19 +++++++++++++++++++ helm_chart_test.go | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/USAGE.md b/docs/USAGE.md index 43932bc..089720d 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -15,7 +15,7 @@ spec: source: address: "https://vault.example.com" path: "foo/bar/(.*)" - namespace: "robertlestak/example" + namespace: "platform/secrets" filters: regex: include: @@ -31,7 +31,7 @@ spec: - vault: address: "https://vault2.example.com" path: "hello/world/$1" - namespace: "robertlestak/example" + namespace: "platform/secrets" - vault: address: "https://vault3.example.com" path: "another/vault" @@ -43,7 +43,7 @@ spec: replicaRegions: ["us-east-1"] - github: repo: "example-repo" - owner: "robertlestak" + owner: "platform-team" - gcp: project: "example-project" name: "example-secret" @@ -157,7 +157,7 @@ The GitHub destination driver will write the secret to a GitHub repository or or - github: repo: "example-repo" env: "" # optional, default empty. Set to a specific environment to sync to within a repo if needed - owner: "robertlestak" # optional, will default to the company org + owner: "platform-team" # optional, will default to the company org org: false # optional, default false. set to true to set org secret rather than repo secret merge: false # optional, default true. false will overwrite existing secrets with values from vault, merge will merge the two ``` @@ -271,7 +271,7 @@ spec: dest: - github: repo: "example-repo" - owner: "robertlestak" + owner: "platform-team" - aws: name: "example-secret" region: "us-west-2" diff --git a/docs/architecture/HLA-microservice.drawio b/docs/architecture/HLA-microservice.drawio index de5ab08..a155410 100644 --- a/docs/architecture/HLA-microservice.drawio +++ b/docs/architecture/HLA-microservice.drawio @@ -75,7 +75,7 @@ - + diff --git a/docs_security_test.go b/docs_security_test.go index f6d5728..4580db1 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -53,6 +53,25 @@ func TestSecurityDocsUseProjectReportingContacts(t *testing.T) { } } +func TestPublicUsageDocsDoNotUseForkEraOwners(t *testing.T) { + for _, path := range []string{"docs/USAGE.md"} { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + for _, forbidden := range []string{ + "robertlestak", + "vault-secret-sync", + } { + if strings.Contains(text, forbidden) { + t.Fatalf("%s should not use fork-era owner or package identifier %q", path, forbidden) + } + } + } +} + func TestSecurityPolicyDocumentsCurrentMajorOnly(t *testing.T) { content, err := os.ReadFile("SECURITY.md") if err != nil { diff --git a/helm_chart_test.go b/helm_chart_test.go index d5516ce..8a67376 100644 --- a/helm_chart_test.go +++ b/helm_chart_test.go @@ -10,6 +10,7 @@ func TestHelmChartUsesSecretSyncAPI(t *testing.T) { paths := []string{ "deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml", "deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml", + "docs/architecture/HLA-microservice.drawio", "docs/USAGE.md", } From c1b69f72f1ca986c293007a73a437daef10af844 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 15:32:19 -0500 Subject: [PATCH 28/42] docs: refresh deployment guide for pipeline runner --- docs/ARCHITECTURE_GAP_ANALYSIS.md | 3 - docs/DEPLOYMENT.md | 289 +++++++++++++++++------------- docs_markdown_test.go | 71 ++++++++ 3 files changed, 232 insertions(+), 131 deletions(-) create mode 100644 docs_markdown_test.go diff --git a/docs/ARCHITECTURE_GAP_ANALYSIS.md b/docs/ARCHITECTURE_GAP_ANALYSIS.md index f4d0495..b3f5cae 100644 --- a/docs/ARCHITECTURE_GAP_ANALYSIS.md +++ b/docs/ARCHITECTURE_GAP_ANALYSIS.md @@ -46,9 +46,6 @@ The main runtime path is the two-phase pipeline: ## Known Remaining Work -- Some historical docs still describe webhook/operator deployment models. Treat - those pages as legacy unless they are refreshed against the current CLI - pipeline. - The Marketplace and action docs should continue to use the component release tag placeholder until the first standalone repository release exists. - The Docker action should eventually move to a digest-pinned image reference diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 0148286..791be88 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -1,174 +1,207 @@ # Deployment -This guide outlines the requirements and different deployment models for the Vault Secrets Sync service. +SecretSync deploys as a `secretsync pipeline` runner. The current production +surface is the CLI, the Docker image, the GitHub Action, or a Kubernetes +workload that invokes the same pipeline command with a mounted configuration +file. -## Getting Started +## Deployment Contract -The service can be configured with either a `YAML` or `JSON` configuration file, or via environment variables. The configuration is unmarshalled into the [`pipeline.Config`](../pkg/pipeline/types.go#L5) struct. An example of a fully configured `YAML` file can be found in [examples/config-full.yaml](../examples/config-full.yaml). To configure via environment variables, you must prefix the environment variable with `SECRETSYNC_` and use `_` to denote nested fields. For example, to set the `queue.type` field, you would set the environment variable `SECRETSYNC_QUEUE_TYPE`. +- Use one pipeline configuration file as the source of truth. +- Validate the configuration before the first apply run. +- Run `--dry-run --diff` before writes in CI and scheduled jobs. +- Enable machine-readable output for automation with `--output json` or + `--output github`. +- Use `--exit-code` when a CI job must distinguish no changes, changes, and + failures. +- Enable metrics with `--metrics-port` for long-running or scheduled runners. -While various examples are provided, the operator intentionally does not ship with a "default" configuration file. This is to ensure that you are aware of the security implications of each component you are enabling. This guide will walk you through each section, what it does, and how to configure it. +## Configuration -### `queue` Configuration +Create a pipeline configuration with Vault source settings, a merge store, AWS +execution context, and targets. See [PIPELINE.md](./PIPELINE.md) for the full +schema. -The service requires a queue for communication between the `Event Server` and the `Sync Operator`. When deployed as a single binary, the `memory` queue will be used by default. This simply uses the operator's internal memory for queuing and processing. For small to moderately sized deployments this may be sufficient, however in more production grade deployments - and when deployed in microservices mode - an external queue must be configured. In all queues, both the event server and sync operator must be able to connect to the queue, and data will only ever flow in one direction (from the outside in, never from the inside out). - -Currently, the following queues are supported: +```yaml +vault: + address: https://vault.example.com/ + namespace: eng/data-platform + auth: + approle: + role_id: ${VAULT_ROLE_ID} + secret_id: ${VAULT_SECRET_ID} + +aws: + region: us-east-1 + execution_context: + type: delegated_admin + account_id: "123456789012" + control_tower: + enabled: true + execution_role: + name: AWSControlTowerExecution -- `memory`: The default queue, which uses the operator's internal memory for queuing and processing. This is only recommended for small to moderately sized deployments, and cannot be used in a microservices deployment model. -- `redis`: The Redis queue uses a Redis instance for queuing and processing. -- `nats`: The NATS queue uses a NATS instance for queuing and processing. -- `sqs`: The SQS queue uses an AWS SQS queue for queuing and processing. +sources: + analytics: + vault: + mount: analytics -An example of a fully configured `YAML` file can be found in [examples/config-full.yaml](../examples/config-full.yaml). Here's an example of a minimal configuration file: +merge_store: + vault: + mount: merged-secrets -```yaml -queue: - type: redis - params: - host: "redis" - port: 6379 - password: "" - db: 0 - tls: - ca: /etc/certs/ca.crt - cert: /etc/certs/client.crt - key: /etc/certs/client.key +targets: + Serverless_Stg: + account_id: "111111111111" + imports: + - analytics ``` -Fields not required in your environment can be omitted. For example, if you are not using TLS, you can omit the `tls` field. If you are not using a password, you can omit the `password` field. - -### `operator` Configuration +Validate before deploying: -The operator is responsible for reconciling the `SecretSync` CRD and handling sync operations. Here's an example of a minimal configuration file: - -```yaml -operator: - enabled: true - workerPoolSize: 10 - numSubscriptions: 10 +```bash +secretsync validate --config config.yaml +secretsync graph --config config.yaml ``` +## Local Or VM Runner -The `workerPoolSize` field is the number of workers that will be spawned to process the events from the queue. The `numSubscriptions` field is the number of subscriptions that will be created to the queue. The number of subscriptions should be equal to or greater than the number of workers. The `workerPoolSize` field should be set to a value that is appropriate for your environment. The default value is `10`. +Install the binary and run the same command used in CI: -### `event` Configuration +```bash +go install github.com/jbcom/secrets-sync/cmd/secretsync@latest + +secretsync pipeline \ + --config config.yaml \ + --dry-run \ + --diff \ + --output json \ + --exit-code +``` -The event server is responsible for listening for audit log events from Vault. The event server is required for the service to operate. It must be accessible by the respective vault instance audit log shippers, and must be able to communicate with the queue. Here's an example of a minimal configuration file: +For an apply run, remove `--dry-run` after reviewing the diff: -```yaml -event: - enabled: true - port: 8080 - security: - enabled: true - tls: - cert: /etc/certs/server.crt - key: /etc/certs/server.key - ca: /etc/certs/ca.crt - clientAuth: require +```bash +secretsync pipeline --config config.yaml --diff --output json ``` -Note that in the examples above, each service has an `enabled` field, this is where you can enable / disable particular components of the service. By default, all components are disabled. However you are still able to re-use a single configuration file across various microservice components by passing the corresponding CLI flag to enable the component rather than modifying the configuration file. +## Docker Runner -### `metrics` Configuration +Mount the configuration read-only and pass credentials through environment +variables, workload identity, or mounted secret files. -The service exposes a metrics endpoint on a dedicated service metrics port (separate from the kubernetes metrics port exposed when running in kubernetes operator mode) to expose Prometheus metrics. Here's an example of a minimal configuration file: - -```yaml -metrics: - port: 8082 +```bash +docker run --rm \ + -v "$PWD/config.yaml:/config.yaml:ro" \ + -e VAULT_ADDR=https://vault.example.com \ + -e VAULT_ROLE_ID="$VAULT_ROLE_ID" \ + -e VAULT_SECRET_ID="$VAULT_SECRET_ID" \ + jbcom/secretssync:v1 \ + pipeline --config /config.yaml --dry-run --diff --output json ``` -Note that the metrics endpoint also supports `security.tls` configuration, it has simply been omitted from the example for brevity. The metrics server also exposes a `/healthz` endpoint that can be used to check the health of the service and its dependencies. +Use the same image for scheduled container platforms. The image entry point is +`secretsync`, and the default command is `pipeline`. -### `stores` Configuration +## GitHub Actions -Each `SecretSync` configuration is entirely self-contained - the `spec` contains all the fields necessary to perform the sync. However you can use the `stores` configuration to set defaults for all `SecretSync` resources. This is useful if you have multiple `SecretSync` resources that share the same configuration. Here's an example of a minimal configuration file: +Use the published Docker action for CI and release pipelines. Keep the action +reference on a release tag and configure AWS/Vault credentials before invoking +SecretSync. ```yaml -stores: - vault: - address: "https://vault.example.com" - - github: - owner: "example-org" +jobs: + secrets: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v6 + - uses: aws-actions/configure-aws-credentials@v5 + with: + role-to-assume: arn:aws:iam::123456789012:role/SecretSyncRunner + aws-region: us-east-1 + - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z + with: + config: config.yaml + dry-run: "true" + compute-diff: "true" + output-format: json + exit-code: "true" ``` -Fields explictly defined in the `SecretSync` resource will take precedence over the defaults set in the `stores` configuration, however if a field is not provided in the `SecretSync` resource, the default value from the `stores` configuration will be used. Defaults are evaluated at runtime and are not persisted back to the backend. This can be both a feature and a bug, depending on your use case. Once you set a central default, be cognizant of the fact that changing the default _will_ change the behavior of existing `SecretSync` resources. For this reason it's generally recommended to not set global defaults and instead rely on fields being explicitly declared on the `SecretSync` resources themselves, unless you know for certain that you want to change the behavior of all resources at once. - -With this said, the fields defined will only work if the operator has the proper access to the stores. For more details on how to configure the operator to access the stores, see the [Security](./SECURITY.md) documentation. - -## Deploying in Kubernetes +See [GITHUB_ACTIONS.md](./GITHUB_ACTIONS.md) for the full action input +reference. -The service can be deployed in Kubernetes using the provided Helm chart. The Helm chart is located in the `deploy/charts` directory of the repository. The chart is designed to be as flexible as possible, and allows you to configure the service using a `values.yaml` file. The chart is designed to be deployed in a microservices architecture, where the webhook service is deployed in one container and the sync operator is deployed in another, however it does support a monolithic deployment as well. The chart also deploys a CRD to enable configuration of the sync service through native Kubernetes resources. +## Kubernetes CronJob -Once you have your `values.yaml` file configured, you can deploy the service using the following command: +For Kubernetes, run SecretSync as a scheduled job unless your environment has a +separate controller managing execution. Mount the pipeline configuration from a +ConfigMap or Secret and provide credentials through your cluster identity model. -```shell -helm install -n secretsync --create-namespace \ - secretsync ./deploy/charts/secretsync \ - -f /path/to/values.yaml +```yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: secretsync +spec: + schedule: "*/30 * * * *" + jobTemplate: + spec: + template: + spec: + restartPolicy: Never + serviceAccountName: secretsync + containers: + - name: secretsync + image: jbcom/secretssync:v1 + args: + - pipeline + - --config + - /config/config.yaml + - --diff + - --output + - json + volumeMounts: + - name: config + mountPath: /config + readOnly: true + volumes: + - name: config + configMap: + name: secretsync-config ``` -Note this will install the `SecretSync` CRD by default. While recommended to use the CRD when deploying in Kubernetes it is _technically_ not required, and so if you do not want to install the CRDs with the rest of the chart, you can pass the `--skip-crds` flag to the `helm install` command. - -The chart will deploy one `Service` object for the event service with a `ClusterIP` type. This must be made accessible from the Vault audit log shipper(s) in whatever manner suits your environment. +For Kubernetes-authenticated Vault access, configure the `vault.auth.kubernetes` +section in the pipeline file and bind the service account to the expected Vault +role. For AWS, prefer IRSA, EKS Pod Identity, or another workload identity +mechanism over static access keys. -You can mount volumes, secrets, and env vars to any of the components through the values file, so if you need to mount a secret to the event server, you can do so through the `values.yaml` file. +## Metrics And Logs -If you're not a fan of using Helm to manage your resources, you can always replace `helm install` with `helm template` and pipe the output to `kubectl apply -f -` to apply the resources directly to your cluster. +Enable metrics when the runner stays alive long enough to be scraped, or when a +platform sidecar captures process metrics: -```shell -helm template -n secretsync \ - secretsync ./deploy/charts/secretsync \ - -f /path/to/values.yaml | kubectl apply -f - +```bash +secretsync pipeline --config config.yaml --metrics-addr 0.0.0.0 --metrics-port 9090 ``` -## Shipping Logs - -This service relies on the audit logs as shipped by HashiCorp Vault. You must have an [audit device](https://developer.hashicorp.com/vault/docs/audit) configured in your Vault instance to ship logs to the service. You must configure the webhook endpoint in your audit device to point to the `/events` endpoint of the service. It is recommended to include the `X-Vault-Tenant` header in the request to the service to identify the source of the event. This is especially important if you are syncing secrets from multiple Vault instances. This is discussed more in [Usage - Source Determination](./USAGE.md#source-determination). Below is a sample Fluentd configuration that ships logs to the service. If you have event server token-based security enabled, you will also need to include the `X-SecretSync-Token` header in the request. While your security posture may vary, it's generally recommended to use multiple layers of security, such as internal networking, IP whitelisting, service mesh RBAC, and token-based security. +Use JSON logs in centralized logging environments: -### Fluentd Configuration Example - -**Token based auth** - -```xml - - @type http - endpoint https://secretsync/events - headers {"x-vault-tenant": "https://vault.example.com", "x-secretsync-token": "99CFF209-9E67-4B22-880F-E15DAC3C1CEE"} - open_timeout 2 - - @type json - - - flush_interval 10s - - +```bash +secretsync pipeline --config config.yaml --log-format json --log-level info ``` -**TLS Client Cert Auth** - -```xml - - @type http - endpoint https://secretsync/events - headers {"x-vault-tenant": "https://vault.example.com"} - tls_ca_cert_path /path/to/ca.crt - tls_client_cert_path /path/to/client.crt - tls_private_key_path /path/to/client.key - open_timeout 2 - - @type json - - - flush_interval 10s - +SecretSync logs operational metadata, paths, targets, counts, durations, and +provider error context. It must not log raw secret values, raw Vault secret +payloads, raw AWS secret payloads, or raw client structures. +## Rollout Checklist - Once your fluentd is up and running, configure your vault audit device to ship logs to the fluentd endpoint. - - -```bash -vault audit enable socket address=fluentd:24224 socket_type=tcp -``` +1. Validate the configuration with `secretsync validate`. +2. Render and review the dependency graph with `secretsync graph`. +3. Run a dry-run diff with machine-readable output. +4. Confirm AWS role assumption and Vault authentication from the runner. +5. Run the apply command with `--diff` enabled for auditability. +6. Monitor exit status, logs, and metrics after each scheduled run. diff --git a/docs_markdown_test.go b/docs_markdown_test.go new file mode 100644 index 0000000..3ec5b98 --- /dev/null +++ b/docs_markdown_test.go @@ -0,0 +1,71 @@ +package secretsync_test + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestMarkdownFencedCodeBlocksAreBalanced(t *testing.T) { + var offenders []string + for _, root := range []string{"README.md", "docs"} { + err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if entry.IsDir() || filepath.Ext(path) != ".md" { + return nil + } + content, readErr := os.ReadFile(path) + if readErr != nil { + return readErr + } + if strings.Count(string(content), "```")%2 != 0 { + offenders = append(offenders, path) + } + return nil + }) + if err != nil { + t.Fatalf("walk %s: %v", root, err) + } + } + + if len(offenders) > 0 { + t.Fatalf("markdown files have unbalanced fenced code blocks: %s", strings.Join(offenders, ", ")) + } +} + +func TestDeploymentGuideUsesCurrentPipelineSurface(t *testing.T) { + content, err := os.ReadFile("docs/DEPLOYMENT.md") + if err != nil { + t.Fatalf("read docs/DEPLOYMENT.md: %v", err) + } + + text := string(content) + for _, required := range []string{ + "secretsync pipeline", + "--dry-run", + "--diff", + "--output json", + "kind: CronJob", + "jbcom/secrets-sync@secrets-sync-vX.Y.Z", + } { + if !strings.Contains(text, required) { + t.Fatalf("docs/DEPLOYMENT.md should document current deployment surface %q", required) + } + } + for _, forbidden := range []string{ + "Vault Secrets Sync service", + "Event Server", + "Sync Operator", + "-operator", + "-events", + "memory queue", + "microservices mode", + } { + if strings.Contains(text, forbidden) { + t.Fatalf("docs/DEPLOYMENT.md should not document stale deployment surface %q", forbidden) + } + } +} From 2e0068193c6af95730c4d3d06e29463eb1c1409e Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 15:37:24 -0500 Subject: [PATCH 29/42] docs: align getting started pipeline config --- README.md | 123 ++++++------ docs/GETTING_STARTED.md | 405 ++++++++++++++++------------------------ docs_markdown_test.go | 35 ++++ 3 files changed, 265 insertions(+), 298 deletions(-) diff --git a/README.md b/README.md index 9ccfc3a..fc8221d 100644 --- a/README.md +++ b/README.md @@ -206,80 +206,73 @@ secretsync pipeline --config pipeline.yaml --dry-run --output side-by-side secretsync pipeline --config pipeline.yaml --metrics-port 9090 # CI/CD mode (exit codes: 0=no changes, 1=changes, 2=errors) -secretsync pipeline --config pipeline.yaml --dry-run --exit-code +secretsync pipeline --config pipeline.yaml --dry-run --diff --output json --exit-code -# Version management -secretsync versions --secret-path "app/database/password" -secretsync sync --version 5 --target production +# Inspect dependency order +secretsync graph --config pipeline.yaml ``` ### Example Configuration ```yaml -# pipeline.yaml - advanced features vault: - address: "https://vault.example.com" - namespace: "admin" + address: https://vault.example.com/ + namespace: admin + auth: + approle: + role_id: ${VAULT_ROLE_ID} + secret_id: ${VAULT_SECRET_ID} aws: - region: "us-east-1" - execution_role_pattern: "arn:aws:iam::{account_id}:role/SecretsSync" - -# Advanced discovery -discovery: - aws_organizations: - enabled: true - tag_filters: - - key: "Environment" - values: ["production", "staging"] - operator: "equals" - - key: "Team" - values: ["platform*"] - operator: "contains" - organizational_units: - - "ou-production-12345" - tag_logic: "AND" - cache_ttl: "1h" - - identity_center: + region: us-east-1 + execution_context: + type: delegated_admin + account_id: "123456789012" + control_tower: enabled: true - region: "us-east-1" - cache_ttl: "30m" - -# Secret versioning -versioning: - enabled: true - s3_bucket: "company-secretsync-versions" - retention_days: 90 - -# Observability -observability: - metrics: - enabled: true - port: 9090 - address: "0.0.0.0" + execution_role: + name: AWSControlTowerExecution merge_store: - vault: - mount: "secret/merged" + s3: + bucket: company-secretsync-merge-store + prefix: merged/ + versioning: + enabled: true + retain_versions: 90 sources: api-keys: vault: - path: "secret/api-keys" + mount: secret + paths: [api-keys] database: vault: - path: "secret/database" + mount: secret + paths: [database] targets: - Staging: - imports: [api-keys, database] + staging: account_id: "111111111111" - - Production: - inherits: Staging - imports: [production-overrides] + imports: [api-keys, database] + + production: account_id: "222222222222" + imports: [staging, production-overrides] + +dynamic_targets: + production-accounts: + discovery: + organizations: + ous: ["ou-production-12345"] + tag_filters: + - key: Environment + values: ["production"] + operator: equals + recursive: true + imports: [production] + region: us-east-1 + secret_prefix: platform/ ``` ## GitHub Actions @@ -364,15 +357,27 @@ See [GitHub Actions documentation](./docs/GITHUB_ACTIONS.md) for complete usage - [🛡️ Security Policy](./SECURITY.md) - Security reporting - [📜 Code of Conduct](./CODE_OF_CONDUCT.md) - Community guidelines -## Helm Deployment +## Kubernetes -```bash -# Add Helm repo -helm repo add secretsync https://jbcom.github.io/secrets-sync +Run SecretSync as a scheduled pipeline runner. See +[docs/DEPLOYMENT.md](./docs/DEPLOYMENT.md) for a complete CronJob example. -# Install -helm install secretsync secretsync/secretsync \ - --set vault.address=https://vault.example.com +```yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: secretsync +spec: + schedule: "*/30 * * * *" + jobTemplate: + spec: + template: + spec: + restartPolicy: Never + containers: + - name: secretsync + image: jbcom/secretssync:v1 + args: ["pipeline", "--config", "/config/config.yaml", "--diff", "--output", "json"] ``` ## Docker diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 8d0da55..dca002b 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -1,38 +1,29 @@ -# Getting Started with SecretSync +# Getting Started With SecretSync -This guide will walk you through setting up SecretSync from scratch to sync secrets from HashiCorp Vault to AWS Secrets Manager. +This guide sets up a current SecretSync pipeline that reads secrets from Vault, +merges them into a merge store, and syncs selected targets into AWS Secrets +Manager. ## Prerequisites -Before you begin, ensure you have: +- HashiCorp Vault with a KV v2 secrets engine. +- AWS credentials from an IAM role, workload identity, or access keys. +- Permission to read the configured Vault mounts. +- Permission to write the target AWS Secrets Manager secrets. -- **HashiCorp Vault** with KV2 secrets engine enabled -- **AWS Account** with Secrets Manager access -- **Vault credentials** (AppRole recommended) -- **AWS credentials** (IAM role or access keys) +## Step 1: Install -## Step 1: Installation - -Choose your preferred installation method: - -### Option A: Go Install +Choose one runtime: ```bash go install github.com/jbcom/secrets-sync/cmd/secretsync@latest ``` -### Option B: Docker - ```bash -# Pull image docker pull jbcom/secretssync:v1 - -# Create alias for easier usage alias secretsync='docker run --rm -v "$PWD":/workspace -w /workspace jbcom/secretssync:v1' ``` -### Option C: Build from Source - ```bash git clone https://github.com/jbcom/secrets-sync.git cd secrets-sync @@ -40,229 +31,140 @@ make build ./bin/secretsync version ``` -## Step 2: Basic Configuration +## Step 2: Create A Pipeline Config -Create a configuration file `config.yaml`: +Create `config.yaml`: ```yaml -# Basic SecretSync configuration vault: - address: "https://your-vault.example.com" - namespace: "admin" # Optional: if using Vault namespaces + address: https://vault.example.com/ + namespace: admin auth: approle: - role_id: "${VAULT_ROLE_ID}" - secret_id: "${VAULT_SECRET_ID}" + role_id: ${VAULT_ROLE_ID} + secret_id: ${VAULT_SECRET_ID} aws: - region: "us-east-1" - # Optional: role to assume for cross-account access - # role_arn: "arn:aws:iam::123456789012:role/SecretSyncRole" + region: us-east-1 + execution_context: + type: delegated_admin + account_id: "123456789012" + control_tower: + enabled: true + execution_role: + name: AWSControlTowerExecution -# Define where to read secrets from sources: app-secrets: vault: - path: "secret/data/myapp" # KV2 path + mount: secret + paths: + - myapp + +merge_store: + vault: + mount: merged-secrets -# Define where to write secrets to targets: production: - aws_secretsmanager: - region: "us-east-1" - # Optional: prefix for secret names - prefix: "myapp/" + account_id: "222222222222" + region: us-east-1 + secret_prefix: myapp/ imports: - app-secrets -``` - -## Step 3: Set Environment Variables -```bash -# Vault credentials -export VAULT_ROLE_ID="your-role-id" -export VAULT_SECRET_ID="your-secret-id" - -# AWS credentials (if not using IAM roles) -export AWS_ACCESS_KEY_ID="your-access-key" -export AWS_SECRET_ACCESS_KEY="your-secret-key" +pipeline: + merge: + parallel: 4 + sync: + parallel: 4 + delete_orphans: false + continue_on_error: true ``` -## Step 4: Validate Configuration +Targets can import from sources or from other targets. Target-to-target imports +are how you model inheritance: -Before running, validate your configuration: +```yaml +targets: + staging: + account_id: "111111111111" + imports: + - app-secrets -```bash -secretsync validate --config config.yaml + production: + account_id: "222222222222" + imports: + - staging ``` -This will check: -- Configuration syntax -- Vault connectivity -- AWS permissions -- Source/target accessibility - -## Step 5: Dry Run - -Perform a dry run to see what changes would be made: +## Step 3: Configure Credentials ```bash -secretsync pipeline --config config.yaml --dry-run -``` - -You should see output like: -``` -Pipeline Diff Summary -===================== - Added: 3 secrets - Modified: 0 secrets - Deleted: 0 secrets - -⚠️ CHANGES DETECTED - -Target: production - + myapp/database-password - + myapp/api-key - + myapp/jwt-secret +export VAULT_ROLE_ID="your-role-id" +export VAULT_SECRET_ID="your-secret-id" +export AWS_REGION="us-east-1" ``` -## Step 6: Execute Sync +Prefer AWS role assumption or workload identity for deployed runners. Use static +AWS access keys only when your environment cannot provide an identity. -If the dry run looks correct, execute the actual sync: +## Step 4: Validate And Inspect ```bash -secretsync pipeline --config config.yaml +secretsync validate --config config.yaml +secretsync graph --config config.yaml ``` -## Step 7: Verify Results +Validation checks the config structure and dependency graph. Add `--check-aws` +when you want validation to test AWS credentials and access. -Check AWS Secrets Manager to confirm your secrets were created: +## Step 5: Dry Run ```bash -# Using AWS CLI -aws secretsmanager list-secrets --query 'SecretList[?starts_with(Name, `myapp/`)]' - -# Or check in AWS Console -# Navigate to AWS Secrets Manager in your region +secretsync pipeline --config config.yaml --dry-run --diff --output json --exit-code ``` -## Next Steps +Exit codes are stable for automation: -### Enable Advanced Features +- `0`: no changes +- `1`: changes detected +- `2`: errors -#### 1. Add Observability +## Step 6: Apply -```bash -# Run with metrics endpoint -secretsync pipeline --config config.yaml --metrics-port 9090 - -# In another terminal, check metrics -curl http://localhost:9090/metrics -curl http://localhost:9090/health -``` - -#### 2. Enhanced Diff Output +After reviewing the dry-run diff, run the apply path: ```bash -# Side-by-side comparison -secretsync pipeline --config config.yaml --dry-run --output side-by-side - -# JSON output for automation -secretsync pipeline --config config.yaml --dry-run --output json -``` - -JSON output is a stable pipeline result envelope with success status, aggregate -secret counts, per-phase `results`, and nested `diff`/`diff_output` fields when -diff computation is enabled. - -#### 3. Secret Versioning - -Add to your config: -```yaml -versioning: - enabled: true - s3_bucket: "my-secretsync-versions" - retention_days: 90 -``` - -#### 4. AWS Organizations Discovery - -```yaml -discovery: - aws_organizations: - enabled: true - tag_filters: - - key: "Environment" - values: ["production", "staging"] - operator: "equals" - cache_ttl: "1h" -``` - -### Set Up CI/CD - -#### GitHub Actions - -Create `.github/workflows/secretsync.yml`: - -```yaml -name: Sync Secrets -on: - schedule: - - cron: '0 */6 * * *' # Every 6 hours - workflow_dispatch: - -jobs: - sync: - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 - with: - role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} - aws-region: us-east-1 - - - name: Sync Secrets - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z - with: - config: config.yaml - env: - VAULT_ROLE_ID: ${{ secrets.VAULT_ROLE_ID }} - VAULT_SECRET_ID: ${{ secrets.VAULT_SECRET_ID }} +secretsync pipeline --config config.yaml --diff --output json ``` ## Common Patterns -### Multi-Environment Setup +### Multi-Environment Inheritance ```yaml sources: base-secrets: vault: - path: "secret/data/base" - + mount: secret + paths: [base] prod-secrets: vault: - path: "secret/data/production" + mount: secret + paths: [production] targets: staging: - aws_secretsmanager: - region: "us-east-1" + account_id: "111111111111" imports: - base-secrets - + production: - aws_secretsmanager: - region: "us-east-1" + account_id: "222222222222" imports: - - base-secrets - - prod-secrets # Production-specific overrides + - staging + - prod-secrets ``` ### Cross-Account Sync @@ -270,90 +172,115 @@ targets: ```yaml targets: dev-account: - aws_secretsmanager: - region: "us-east-1" - role_arn: "arn:aws:iam::111111111111:role/SecretSyncRole" + account_id: "111111111111" + region: us-east-1 + role_arn: arn:aws:iam::111111111111:role/SecretSyncRole imports: - dev-secrets - + prod-account: - aws_secretsmanager: - region: "us-east-1" - role_arn: "arn:aws:iam::222222222222:role/SecretSyncRole" + account_id: "222222222222" + region: us-east-1 + role_arn: arn:aws:iam::222222222222:role/SecretSyncRole imports: - prod-secrets ``` -### Merge Store Pattern +### S3 Merge Store With Versioning ```yaml -# Use S3 as merge store for complex inheritance merge_store: s3: - bucket: "my-secretsync-merge-store" - prefix: "merged/" - region: "us-east-1" - -targets: - staging: - imports: [base-secrets] - - production: - inherits: staging # Inherit from staging's merged output - imports: [prod-overrides] + bucket: my-secretsync-merge-store + prefix: merged/ + kms_key_id: alias/secretsync + versioning: + enabled: true + retain_versions: 90 ``` -## Troubleshooting +### Dynamic AWS Organizations Targets -### Common Issues - -#### "Vault authentication failed" -- Verify `VAULT_ROLE_ID` and `VAULT_SECRET_ID` are correct -- Check Vault policies allow access to specified paths -- Ensure Vault address is reachable +```yaml +dynamic_targets: + production-accounts: + discovery: + organizations: + ous: + - ou-abcd-production + tag_filters: + - key: Environment + values: ["production"] + operator: equals + recursive: true + imports: + - app-secrets + region: us-east-1 + secret_prefix: myapp/ +``` -#### "AWS access denied" -- Verify AWS credentials are configured -- Check IAM permissions for Secrets Manager -- Ensure region is correct +Run with discovery enabled: -#### "Secret not found" -- Verify Vault path exists and is accessible -- Check KV2 engine is enabled at the mount -- Ensure path format is correct (`secret/data/path` for KV2) +```bash +secretsync pipeline --config config.yaml --discover --dry-run --diff +``` -### Debug Mode +## GitHub Actions -Enable debug logging for more details: +```yaml +name: Sync Secrets +on: + schedule: + - cron: "0 */6 * * *" + workflow_dispatch: -```bash -secretsync pipeline --config config.yaml --log-level debug +jobs: + sync: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 + with: + role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} + aws-region: us-east-1 + - uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z + with: + config: config.yaml + dry-run: "true" + compute-diff: "true" + output-format: json + exit-code: "true" + env: + VAULT_ROLE_ID: ${{ secrets.VAULT_ROLE_ID }} + VAULT_SECRET_ID: ${{ secrets.VAULT_SECRET_ID }} ``` -### Validate Permissions +## Troubleshooting -Test individual components: +### Vault authentication failed -```bash -# Test Vault connectivity -vault auth -method=approle role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID -vault kv list secret/ +- Verify `VAULT_ROLE_ID` and `VAULT_SECRET_ID`. +- Confirm the AppRole can read the configured mounts and paths. +- Confirm Vault address and namespace are reachable from the runner. -# Test AWS connectivity -aws secretsmanager list-secrets --region us-east-1 -``` +### AWS access denied -## Getting Help +- Confirm the runner identity can assume the configured target role. +- Check Secrets Manager create, update, list, and delete permissions. +- Confirm the configured region and account IDs. -- **Documentation**: [Full docs](https://github.com/jbcom/secrets-sync/docs) -- **Examples**: [Configuration examples](https://github.com/jbcom/secrets-sync/examples) -- **Issues**: [GitHub Issues](https://github.com/jbcom/secrets-sync/issues) +### No changes detected unexpectedly -## What's Next? +- Run with `--output side-by-side` for a human diff. +- Check target imports and source path spelling. +- Run `secretsync graph --config config.yaml` to verify dependency order. -- Explore [advanced configuration options](./PIPELINE.md) -- Set up [monitoring and observability](./OBSERVABILITY.md) -- Learn about [deployment patterns](./DEPLOYMENT.md) -- Integrate with [GitHub Actions](./GITHUB_ACTIONS.md) +## Next Steps -Welcome to SecretSync! 🚀 +- Read [PIPELINE.md](./PIPELINE.md) for the full configuration reference. +- Read [DEPLOYMENT.md](./DEPLOYMENT.md) for production deployment patterns. +- Read [OBSERVABILITY.md](./OBSERVABILITY.md) for metrics and logging. +- Read [GITHUB_ACTIONS.md](./GITHUB_ACTIONS.md) for CI integration. diff --git a/docs_markdown_test.go b/docs_markdown_test.go index 3ec5b98..faff05b 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -69,3 +69,38 @@ func TestDeploymentGuideUsesCurrentPipelineSurface(t *testing.T) { } } } + +func TestGettingStartedUsesCurrentPipelineConfigShape(t *testing.T) { + paths := []string{"README.md", "docs/GETTING_STARTED.md"} + + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + text := string(content) + for _, required := range []string{ + "merge_store:", + "account_id:", + "secret_prefix:", + "dynamic_targets:", + } { + if !strings.Contains(text, required) { + t.Fatalf("%s should document current pipeline config %q", path, required) + } + } + for _, forbidden := range []string{ + "aws_secretsmanager:", + "inherits:", + "discovery:\n aws_organizations:", + "versioning:\n enabled: true\n s3_bucket:", + "secretsync versions", + "secretsync sync --version", + } { + if strings.Contains(text, forbidden) { + t.Fatalf("%s should not document stale config shape %q", path, forbidden) + } + } + } +} From b5912a06bdbb3249992a892d7227dc597d91c08f Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 15:51:21 -0500 Subject: [PATCH 30/42] fix: align kubernetes surface with pipeline runner --- README.md | 12 +- api/v1alpha1/register.go | 37 -- api/v1alpha1/secretsync_types.go | 148 ------ api/v1alpha1/zz_generated.deepcopy.go | 440 ------------------ deploy/charts/secretsync/Chart.yaml | 8 - .../charts/secretsync-events/.helmignore | 23 - .../charts/secretsync-events/Chart.yaml | 24 - .../secretsync-events/templates/_helpers.tpl | 88 ---- .../templates/configmap.yaml | 12 - .../templates/deployment.yaml | 91 ---- .../secretsync-events/templates/hpa.yaml | 32 -- .../secretsync-events/templates/service.yaml | 15 - .../templates/serviceaccount.yaml | 12 - .../charts/secretsync-events/values.yaml | 190 -------- .../charts/secretsync-operator/.helmignore | 23 - .../charts/secretsync-operator/Chart.yaml | 24 - ...cretsync.extendeddata.dev_secretsyncs.yaml | 328 ------------- .../secretsync-operator/templates/NOTES.txt | 5 - .../templates/_helpers.tpl | 100 ---- .../templates/clusterrole.yaml | 21 - .../templates/clusterrolebinding.yaml | 16 - .../templates/configmap.yaml | 12 - .../templates/deployment.yaml | 95 ---- .../secretsync-operator/templates/hpa.yaml | 32 -- .../templates/serviceaccount.yaml | 12 - .../charts/secretsync-operator/values.yaml | 183 -------- .../charts/secretsync/templates/_helpers.tpl | 44 +- .../secretsync/templates/configmap.yaml | 6 +- .../charts/secretsync/templates/cronjob.yaml | 118 +++++ .../secretsync/templates/serviceaccount.yaml | 13 + deploy/charts/secretsync/values.yaml | 395 +++------------- docs/FAQ.md | 86 ++-- docs/ROADMAP.md | 8 +- docs/SECURITY.md | 80 +--- docs/TWO_PHASE_ARCHITECTURE.md | 36 +- docs/USAGE.md | 368 ++++----------- examples/config-full.yaml | 179 +++---- examples/organizations-discovery.yaml | 36 +- examples/vault-to-aws-secrets.yaml | 49 +- examples/vault-to-github.yaml | 18 - examples/vault-to-vault.yaml | 16 - examples_config_test.go | 81 ++++ helm_chart_test.go | 120 ++++- 43 files changed, 785 insertions(+), 2851 deletions(-) delete mode 100644 api/v1alpha1/register.go delete mode 100644 api/v1alpha1/secretsync_types.go delete mode 100644 api/v1alpha1/zz_generated.deepcopy.go delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/.helmignore delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/Chart.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/_helpers.tpl delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/configmap.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/deployment.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/hpa.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/service.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/templates/serviceaccount.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-events/values.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/.helmignore delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/Chart.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/NOTES.txt delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/_helpers.tpl delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrolebinding.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/configmap.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/deployment.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/hpa.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/templates/serviceaccount.yaml delete mode 100644 deploy/charts/secretsync/charts/secretsync-operator/values.yaml create mode 100644 deploy/charts/secretsync/templates/cronjob.yaml create mode 100644 deploy/charts/secretsync/templates/serviceaccount.yaml delete mode 100644 examples/vault-to-github.yaml delete mode 100644 examples/vault-to-vault.yaml create mode 100644 examples_config_test.go diff --git a/README.md b/README.md index fc8221d..92750b6 100644 --- a/README.md +++ b/README.md @@ -78,15 +78,16 @@ SecretSync originated as a fork of [robertlestak/vault-secret-sync](https://gith - Dynamic target discovery (AWS Organizations, Identity Center) - Comprehensive diff/dry-run system with CI/CD integration - DeepMerge semantics for secret aggregation -- Kubernetes operator with CRD support +- Kubernetes CronJob and Helm pipeline-runner deployment ## Supported Secret Stores -| Store | Source | Target | Merge Store | -|-------|--------|--------|-------------| -| HashiCorp Vault (KV2) | ✅ | ✅ | ✅ | +| Store | Source | Sync Target | Merge Store | +|-------|--------|-------------|-------------| +| HashiCorp Vault (KV2) | ✅ | ❌ | ✅ | | AWS Secrets Manager | ✅ | ✅ | ❌ | | AWS S3 | ❌ | ❌ | ✅ | +| AWS Organizations | Discovery | ❌ | ❌ | | AWS Identity Center | Discovery | ❌ | ❌ | ## Two-Phase Pipeline Architecture @@ -104,8 +105,7 @@ SecretSync originated as a fork of [robertlestak/vault-secret-sync](https://gith │ SYNC PHASE │ │ Merge Store ──┬──▶ AWS Account 1 (via STS AssumeRole) │ │ (or Source) ├──▶ AWS Account 2 │ -│ ├──▶ Vault Cluster │ -│ └──▶ GCP Project │ +│ └──▶ AWS Account 3 │ └─────────────────────────────────────────────────────────────────┘ ``` diff --git a/api/v1alpha1/register.go b/api/v1alpha1/register.go deleted file mode 100644 index 69ffff5..0000000 --- a/api/v1alpha1/register.go +++ /dev/null @@ -1,37 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: "secretsync.extendeddata.dev", Version: "v1alpha1"} - -// Kind takes an unqualified kind and returns back a Group qualified GroupKind -func Kind(kind string) schema.GroupKind { - return SchemeGroupVersion.WithKind(kind).GroupKind() -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -var ( - // SchemeBuilder initializes a scheme builder - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - // AddToScheme is a global function that registers this API group & version to a scheme - AddToScheme = SchemeBuilder.AddToScheme -) - -// Adds the list of known types to Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &SecretSync{}, - &SecretSyncList{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/api/v1alpha1/secretsync_types.go b/api/v1alpha1/secretsync_types.go deleted file mode 100644 index 48cd477..0000000 --- a/api/v1alpha1/secretsync_types.go +++ /dev/null @@ -1,148 +0,0 @@ -// +k8s:deepcopy-gen=package -// +groupName=secretsync.extendeddata.dev -package v1alpha1 - -import ( - "github.com/jbcom/secrets-sync/pkg/client/aws" - "github.com/jbcom/secrets-sync/pkg/client/vault" - "github.com/jbcom/secrets-sync/pkg/discovery/identitycenter" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +genclient - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:resource:path=secretsyncs,scope=Namespaced,shortName=ss -// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`,description="Current status of the SecretSync" -// +kubebuilder:printcolumn:name="SyncDestinations",type=integer,JSONPath=`.status.syncDestinations`,description="Number of destinations synced" - -// SecretSync is the Schema for the secretsyncs API -type SecretSync struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SecretSyncSpec `json:"spec,omitempty"` - Status SecretSyncStatus `json:"status,omitempty"` -} - -type NotificationEvent string - -const ( - NotificationEventSyncSuccess NotificationEvent = "success" - NotificationEventSyncFailure NotificationEvent = "failure" -) - -type StoreConfig struct { - AWS *aws.AwsClient `json:"aws,omitempty" yaml:"aws,omitempty"` - IdentityCenter *identitycenter.IdentityCenterClient `json:"awsIdentityCenter,omitempty" yaml:"awsIdentityCenter,omitempty"` - Vault *vault.VaultClient `json:"vault,omitempty" yaml:"vault,omitempty"` -} - -type RegexpFilterConfig struct { - Include []string `json:"include,omitempty" yaml:"include,omitempty"` - Exclude []string `json:"exclude,omitempty" yaml:"exclude,omitempty"` -} - -type PathFilterConfig struct { - Include []string `json:"include,omitempty" yaml:"include,omitempty"` - Exclude []string `json:"exclude,omitempty" yaml:"exclude,omitempty"` -} - -type FilterConfig struct { - Regex *RegexpFilterConfig `json:"regex,omitempty" yaml:"regex,omitempty"` - Path *PathFilterConfig `json:"path,omitempty" yaml:"path,omitempty"` -} - -type RenameTransform struct { - From string `json:"from"` - To string `json:"to"` -} - -type TransformSpec struct { - Include []string `yaml:"include,omitempty" json:"include,omitempty"` - Exclude []string `yaml:"exclude,omitempty" json:"exclude,omitempty"` - Rename []RenameTransform `json:"rename,omitempty"` - Template *string `json:"template,omitempty"` -} - -// Webhook represents the configuration for a webhook. -type WebhookNotification struct { - Events []NotificationEvent `json:"events"` - URL string `yaml:"url,omitempty" json:"url,omitempty"` - Method string `yaml:"method,omitempty" json:"method,omitempty"` - Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"` - HeaderSecret *string `yaml:"headerSecret,omitempty" json:"headerSecret,omitempty"` - Body string `yaml:"body,omitempty" json:"body,omitempty"` - ExcludeBody bool `yaml:"excludeBody,omitempty" json:"excludeBody,omitempty"` -} - -type EmailNotification struct { - Events []NotificationEvent `json:"events"` - To string `yaml:"to,omitempty" json:"to,omitempty"` - From string `yaml:"from,omitempty" json:"from,omitempty"` - Subject string `yaml:"subject,omitempty" json:"subject,omitempty"` - Body string `yaml:"body,omitempty" json:"body,omitempty"` - - Host string `yaml:"host,omitempty" json:"host,omitempty"` - Port int `yaml:"port,omitempty" json:"port,omitempty"` - Username string `yaml:"username,omitempty" json:"username,omitempty"` - Password string `yaml:"password,omitempty" json:"password,omitempty"` - InsecureSkipVerify bool `yaml:"insecureSkipVerify,omitempty" json:"insecureSkipVerify,omitempty"` -} - -type SlackNotification struct { - Events []NotificationEvent `json:"events"` - URL *string `yaml:"url,omitempty" json:"url,omitempty"` - URLSecret *string `yaml:"urlSecret,omitempty" json:"urlSecret,omitempty"` - URLSecretKey *string `yaml:"urlSecretKey,omitempty" json:"urlSecretKey,omitempty"` - Body string `yaml:"body,omitempty" json:"body,omitempty"` -} - -type NotificationMessage struct { - Event NotificationEvent `json:"event"` - Message string `json:"message"` - SecretSync SecretSync `json:"secretSync"` -} - -type NotificationSpec struct { - Webhook *WebhookNotification `json:"webhook,omitempty"` - Email *EmailNotification `json:"email,omitempty"` - Slack *SlackNotification `json:"slack,omitempty"` -} - -// +kubebuilder:object:generate=true - -// SecretSyncSpec defines the desired state of SecretSync -type SecretSyncSpec struct { - Source *vault.VaultClient `yaml:"source" json:"source"` - Dest []*StoreConfig `yaml:"dest" json:"dest"` - SyncDelete *bool `yaml:"syncDelete,omitempty" json:"syncDelete,omitempty"` - DryRun *bool `yaml:"dryRun,omitempty" json:"dryRun,omitempty"` - Suspend *bool `yaml:"suspend,omitempty" json:"suspend,omitempty"` - Filters *FilterConfig `yaml:"filters,omitempty" json:"filters,omitempty"` - Transforms *TransformSpec `json:"transforms,omitempty"` - Notifications []*NotificationSpec `json:"notifications,omitempty"` - NotificationsTemplate *string `json:"notificationsTemplate,omitempty"` -} - -// +kubebuilder:object:generate=true - -// SecretSyncStatus defines the observed state of SecretSync -type SecretSyncStatus struct { - Status string `json:"status,omitempty"` - LastSyncTime metav1.Time `json:"lastSyncTime,omitempty"` - SyncDestinations int `json:"syncDestinations,omitempty"` - Hash string `json:"hash,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:object:root=true - -// SecretSyncList contains a list of SecretSync -type SecretSyncList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []SecretSync `json:"items"` -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 58d7596..0000000 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,440 +0,0 @@ -//go:build !ignore_autogenerated - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EmailNotification) DeepCopyInto(out *EmailNotification) { - *out = *in - if in.Events != nil { - in, out := &in.Events, &out.Events - *out = make([]NotificationEvent, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmailNotification. -func (in *EmailNotification) DeepCopy() *EmailNotification { - if in == nil { - return nil - } - out := new(EmailNotification) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterConfig) DeepCopyInto(out *FilterConfig) { - *out = *in - if in.Regex != nil { - in, out := &in.Regex, &out.Regex - *out = new(RegexpFilterConfig) - (*in).DeepCopyInto(*out) - } - if in.Path != nil { - in, out := &in.Path, &out.Path - *out = new(PathFilterConfig) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterConfig. -func (in *FilterConfig) DeepCopy() *FilterConfig { - if in == nil { - return nil - } - out := new(FilterConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationMessage) DeepCopyInto(out *NotificationMessage) { - *out = *in - in.SecretSync.DeepCopyInto(&out.SecretSync) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationMessage. -func (in *NotificationMessage) DeepCopy() *NotificationMessage { - if in == nil { - return nil - } - out := new(NotificationMessage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationSpec) DeepCopyInto(out *NotificationSpec) { - *out = *in - if in.Webhook != nil { - in, out := &in.Webhook, &out.Webhook - *out = new(WebhookNotification) - (*in).DeepCopyInto(*out) - } - if in.Email != nil { - in, out := &in.Email, &out.Email - *out = new(EmailNotification) - (*in).DeepCopyInto(*out) - } - if in.Slack != nil { - in, out := &in.Slack, &out.Slack - *out = new(SlackNotification) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationSpec. -func (in *NotificationSpec) DeepCopy() *NotificationSpec { - if in == nil { - return nil - } - out := new(NotificationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PathFilterConfig) DeepCopyInto(out *PathFilterConfig) { - *out = *in - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Exclude != nil { - in, out := &in.Exclude, &out.Exclude - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PathFilterConfig. -func (in *PathFilterConfig) DeepCopy() *PathFilterConfig { - if in == nil { - return nil - } - out := new(PathFilterConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RegexpFilterConfig) DeepCopyInto(out *RegexpFilterConfig) { - *out = *in - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Exclude != nil { - in, out := &in.Exclude, &out.Exclude - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegexpFilterConfig. -func (in *RegexpFilterConfig) DeepCopy() *RegexpFilterConfig { - if in == nil { - return nil - } - out := new(RegexpFilterConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RenameTransform) DeepCopyInto(out *RenameTransform) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RenameTransform. -func (in *RenameTransform) DeepCopy() *RenameTransform { - if in == nil { - return nil - } - out := new(RenameTransform) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SlackNotification) DeepCopyInto(out *SlackNotification) { - *out = *in - if in.Events != nil { - in, out := &in.Events, &out.Events - *out = make([]NotificationEvent, len(*in)) - copy(*out, *in) - } - if in.URL != nil { - in, out := &in.URL, &out.URL - *out = new(string) - **out = **in - } - if in.URLSecret != nil { - in, out := &in.URLSecret, &out.URLSecret - *out = new(string) - **out = **in - } - if in.URLSecretKey != nil { - in, out := &in.URLSecretKey, &out.URLSecretKey - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackNotification. -func (in *SlackNotification) DeepCopy() *SlackNotification { - if in == nil { - return nil - } - out := new(SlackNotification) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *StoreConfig) DeepCopyInto(out *StoreConfig) { - *out = *in - if in.AWS != nil { - in, out := &in.AWS, &out.AWS - *out = (*in).DeepCopy() - } - if in.IdentityCenter != nil { - in, out := &in.IdentityCenter, &out.IdentityCenter - *out = (*in).DeepCopy() - } - if in.Vault != nil { - in, out := &in.Vault, &out.Vault - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StoreConfig. -func (in *StoreConfig) DeepCopy() *StoreConfig { - if in == nil { - return nil - } - out := new(StoreConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TransformSpec) DeepCopyInto(out *TransformSpec) { - *out = *in - if in.Include != nil { - in, out := &in.Include, &out.Include - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Exclude != nil { - in, out := &in.Exclude, &out.Exclude - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Rename != nil { - in, out := &in.Rename, &out.Rename - *out = make([]RenameTransform, len(*in)) - copy(*out, *in) - } - if in.Template != nil { - in, out := &in.Template, &out.Template - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TransformSpec. -func (in *TransformSpec) DeepCopy() *TransformSpec { - if in == nil { - return nil - } - out := new(TransformSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretSync) DeepCopyInto(out *SecretSync) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSync. -func (in *SecretSync) DeepCopy() *SecretSync { - if in == nil { - return nil - } - out := new(SecretSync) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecretSync) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretSyncList) DeepCopyInto(out *SecretSyncList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]SecretSync, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSyncList. -func (in *SecretSyncList) DeepCopy() *SecretSyncList { - if in == nil { - return nil - } - out := new(SecretSyncList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecretSyncList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretSyncSpec) DeepCopyInto(out *SecretSyncSpec) { - *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = (*in).DeepCopy() - } - if in.Dest != nil { - in, out := &in.Dest, &out.Dest - *out = make([]*StoreConfig, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(StoreConfig) - (*in).DeepCopyInto(*out) - } - } - } - if in.SyncDelete != nil { - in, out := &in.SyncDelete, &out.SyncDelete - *out = new(bool) - **out = **in - } - if in.DryRun != nil { - in, out := &in.DryRun, &out.DryRun - *out = new(bool) - **out = **in - } - if in.Suspend != nil { - in, out := &in.Suspend, &out.Suspend - *out = new(bool) - **out = **in - } - if in.Filters != nil { - in, out := &in.Filters, &out.Filters - *out = new(FilterConfig) - (*in).DeepCopyInto(*out) - } - if in.Transforms != nil { - in, out := &in.Transforms, &out.Transforms - *out = new(TransformSpec) - (*in).DeepCopyInto(*out) - } - if in.Notifications != nil { - in, out := &in.Notifications, &out.Notifications - *out = make([]*NotificationSpec, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(NotificationSpec) - (*in).DeepCopyInto(*out) - } - } - } - if in.NotificationsTemplate != nil { - in, out := &in.NotificationsTemplate, &out.NotificationsTemplate - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSyncSpec. -func (in *SecretSyncSpec) DeepCopy() *SecretSyncSpec { - if in == nil { - return nil - } - out := new(SecretSyncSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecretSyncStatus) DeepCopyInto(out *SecretSyncStatus) { - *out = *in - in.LastSyncTime.DeepCopyInto(&out.LastSyncTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretSyncStatus. -func (in *SecretSyncStatus) DeepCopy() *SecretSyncStatus { - if in == nil { - return nil - } - out := new(SecretSyncStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WebhookNotification) DeepCopyInto(out *WebhookNotification) { - *out = *in - if in.Events != nil { - in, out := &in.Events, &out.Events - *out = make([]NotificationEvent, len(*in)) - copy(*out, *in) - } - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.HeaderSecret != nil { - in, out := &in.HeaderSecret, &out.HeaderSecret - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookNotification. -func (in *WebhookNotification) DeepCopy() *WebhookNotification { - if in == nil { - return nil - } - out := new(WebhookNotification) - in.DeepCopyInto(out) - return out -} diff --git a/deploy/charts/secretsync/Chart.yaml b/deploy/charts/secretsync/Chart.yaml index 6584c4c..4de39c1 100644 --- a/deploy/charts/secretsync/Chart.yaml +++ b/deploy/charts/secretsync/Chart.yaml @@ -4,11 +4,3 @@ description: Universal secrets synchronization pipeline for multi-cloud secret m type: application version: 0.1.0 appVersion: "0.1.0" - -dependencies: - - name: secretsync-events - version: 0.1.0 - condition: secretsync-events.enabled - - name: secretsync-operator - version: 0.1.0 - condition: secretsync-operator.enabled \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/.helmignore b/deploy/charts/secretsync/charts/secretsync-events/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deploy/charts/secretsync/charts/secretsync-events/Chart.yaml b/deploy/charts/secretsync/charts/secretsync-events/Chart.yaml deleted file mode 100644 index 5b6eed3..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/Chart.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v2 -name: secretsync-events -description: SecretSync events server for webhook-based secret synchronization - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/_helpers.tpl b/deploy/charts/secretsync/charts/secretsync-events/templates/_helpers.tpl deleted file mode 100644 index 2ffbf31..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/_helpers.tpl +++ /dev/null @@ -1,88 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "secretsync-events.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "secretsync-events.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "secretsync-events.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "secretsync-events.labels" -}} -helm.sh/chart: {{ include "secretsync-events.chart" . }} -{{ include "secretsync-events.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "secretsync-events.selectorLabels" -}} -app.kubernetes.io/name: {{ include "secretsync-events.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "secretsync-events.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "secretsync-events.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} - -{{/* -Simplify the definition of the event port -*/}} -{{- define "secretsync-events.containerPort" -}} -{{- default "8080" .Values.containerPort }} -{{- end }} - -{{/* -Simplify the definition of the event port -*/}} -{{- define "secretsync-events.metricsPort" -}} -{{- default "9090" .Values.metricsPort }} -{{- end }} - - -{{/* -Create the name of the configMap to use -*/}} -{{- define "secretsync-events.configMapName" -}} -{{- if .Values.existingConfigMap }} -{{- .Values.existingConfigMap -}} -{{- else }} -{{- include "secretsync-events.fullname" . -}} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/configmap.yaml b/deploy/charts/secretsync/charts/secretsync-events/templates/configmap.yaml deleted file mode 100644 index 47b9c93..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/configmap.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if (eq .Values.existingConfigMap "") }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "secretsync-events.configMapName" . }} - labels: - {{- include "secretsync-events.labels" . | nindent 4 }} -data: - config.yaml: | - {{- .Values.config | toYaml | nindent 4 }} -{{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/deployment.yaml b/deploy/charts/secretsync/charts/secretsync-events/templates/deployment.yaml deleted file mode 100644 index 84317fa..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/deployment.yaml +++ /dev/null @@ -1,91 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "secretsync-events.fullname" . }} - labels: - {{- include "secretsync-events.labels" . | nindent 4 }} - {{- with .Values.deploymentAnnotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "secretsync-events.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "secretsync-events.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "secretsync-events.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - args: ["-config", "/config/config.yaml", "-events"] - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - containerPort: {{ include "secretsync-events.containerPort" . }} - name: http - - containerPort: {{ include "secretsync-events.metricsPort" . }} - name: metrics - livenessProbe: - httpGet: - path: /healthz - port: metrics - readinessProbe: - httpGet: - path: /healthz - port: metrics - {{- with .Values.env }} - env: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.envFrom }} - envFrom: - {{- toYaml . | nindent 12 }} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - name: config - mountPath: /config - readOnly: true - {{- with .Values.extraVolumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: config - configMap: - name: {{ include "secretsync-events.configMapName" . }} - defaultMode: 420 - optional: true - {{- with .Values.extraVolumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/hpa.yaml b/deploy/charts/secretsync/charts/secretsync-events/templates/hpa.yaml deleted file mode 100644 index e515a68..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "secretsync-events.fullname" . }} - labels: - {{- include "secretsync-events.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "secretsync-events.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/service.yaml b/deploy/charts/secretsync/charts/secretsync-events/templates/service.yaml deleted file mode 100644 index 5ca498c..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "secretsync-events.fullname" . }} - labels: - {{- include "secretsync-events.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "secretsync-events.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/templates/serviceaccount.yaml b/deploy/charts/secretsync/charts/secretsync-events/templates/serviceaccount.yaml deleted file mode 100644 index e3f5900..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "secretsync-events.serviceAccountName" . }} - labels: - {{- include "secretsync-events.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-events/values.yaml b/deploy/charts/secretsync/charts/secretsync-events/values.yaml deleted file mode 100644 index a70d986..0000000 --- a/deploy/charts/secretsync/charts/secretsync-events/values.yaml +++ /dev/null @@ -1,190 +0,0 @@ -# Default values for secretsync-events. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -existingConfigMap: "" -config: {} -# # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# log: -# level: "debug" # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# format: "json" # The format of the log output. Can be one of "json" or "text" -# events: true # Whether to log events. - -# # Configuration for the event server. -# events: -# # Whether the event server is enabled. -# enabled: true -# # The port the event server listens on. -# port: 8080 -# # Security settings for the event server. -# security: -# # Whether security is enabled for the event server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the event server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" -# # Whether to deduplicate events. -# dedupe: true - -# # Configuration for the operator. -# operator: -# # Whether the operator is enabled. -# enabled: true -# # Backend configuration for the operator. -# workerPoolSize: 10 -# # The number of subscriptions to use. -# numSubscriptions: 10 -# backend: -# # The type of backend to use. -# type: "your-backend-type" -# # Parameters for the backend. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the stores. -# stores: - # aws: - # region: "us-west-2" - - # github: - # installId: 12345 - # appId: 67890 - # privateKeyPath: "/path/to/private/key" - -# # Configuration for the queue. -# queue: -# # The type of queue to use. -# type: "your-queue-type" -# # Parameters for the queue. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the metrics server. -# metrics: -# # The port the metrics server listens on. -# port: 9090 -# # Security settings for the metrics server. -# security: -# # Whether security is enabled for the metrics server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the metrics server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" - -# notifications: -# email: -# enabled: true -# host: "smtp.example.com" -# port: 587 -# username: "your-email@example.com" -# password: "your-email-password" -# from: "your-email@example.com" -# to: "recipient@example.com" -# subject: "Notification Subject" -# body: "This is the notification body." -# slack: -# enabled: true -# url: "https://hooks.slack.example.com/services/xxx/xxx/xxx" -# message: "This is the notification message." -# webhook: -# enabled: true -# url: "https://example.com/webhook" -# method: "POST" -# headers: -# Content-Type: "application/json" -# body: | -# { -# "status": "{{ .Status }}", -# "message": "{{ .Message }}" -# } - - - -replicaCount: 1 - -image: - repository: docker.io/jbcom/secretssync - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -deploymentAnnotations: {} -podAnnotations: {} - -podSecurityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - fsGroup: 65534 - -securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 65534 - -containerPort: 8080 - -service: - type: ClusterIP - port: 8080 - -resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 128Mi - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -env: [] -envFrom: [] -extraVolumeMounts: [] -extraVolumes: [] \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/.helmignore b/deploy/charts/secretsync/charts/secretsync-operator/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deploy/charts/secretsync/charts/secretsync-operator/Chart.yaml b/deploy/charts/secretsync/charts/secretsync-operator/Chart.yaml deleted file mode 100644 index 80b6078..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/Chart.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v2 -name: secretsync-operator -description: A Helm chart for managing the SecretSync Operator - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "0.1.0" diff --git a/deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml b/deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml deleted file mode 100644 index 3b484cf..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/crds/secretsync.extendeddata.dev_secretsyncs.yaml +++ /dev/null @@ -1,328 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: (devel) - name: secretsyncs.secretsync.extendeddata.dev -spec: - group: secretsync.extendeddata.dev - names: - kind: SecretSync - listKind: SecretSyncList - plural: secretsyncs - shortNames: - - ss - singular: secretsync - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: Current status of the SecretSync - jsonPath: .status.status - name: Status - type: string - - description: Number of destinations synced - jsonPath: .status.syncDestinations - name: SyncDestinations - type: integer - name: v1alpha1 - schema: - openAPIV3Schema: - description: SecretSync is the Schema for the secretsyncs API - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: SecretSyncSpec defines the desired state of SecretSync - properties: - dest: - items: - properties: - aws: - properties: - encryptionKey: - type: string - name: - type: string - region: - type: string - replicaRegions: - items: - type: string - type: array - roleArn: - type: string - tags: - additionalProperties: - type: string - type: object - type: object - gcp: - properties: - labels: - additionalProperties: - type: string - type: object - name: - type: string - project: - type: string - replicationLocations: - items: - type: string - type: array - type: object - github: - properties: - appId: - type: integer - env: - type: string - installId: - type: integer - merge: - type: boolean - org: - type: boolean - orgInstallIds: - additionalProperties: - type: integer - type: object - owner: - type: string - privateKey: - type: string - privateKeyPath: - type: string - repo: - type: string - type: object - http: - properties: - headerSecret: - type: string - headers: - additionalProperties: - type: string - type: object - method: - type: string - successCodes: - items: - type: integer - type: array - template: - type: string - url: - type: string - type: object - vault: - description: VaultClient is a single self-contained vault client - properties: - address: - type: string - authMethod: - type: string - cidr: - type: string - merge: - type: boolean - namespace: - type: string - path: - type: string - role: - type: string - ttl: - type: string - type: object - type: object - type: array - dryRun: - type: boolean - filters: - properties: - path: - properties: - exclude: - items: - type: string - type: array - include: - items: - type: string - type: array - type: object - regex: - properties: - exclude: - items: - type: string - type: array - include: - items: - type: string - type: array - type: object - type: object - notifications: - items: - properties: - email: - properties: - body: - type: string - events: - items: - type: string - type: array - from: - type: string - host: - type: string - insecureSkipVerify: - type: boolean - password: - type: string - port: - type: integer - subject: - type: string - to: - type: string - username: - type: string - required: - - events - type: object - slack: - properties: - body: - type: string - events: - items: - type: string - type: array - url: - type: string - urlSecret: - type: string - urlSecretKey: - type: string - required: - - events - type: object - webhook: - description: Webhook represents the configuration for a webhook. - properties: - body: - type: string - events: - items: - type: string - type: array - excludeBody: - type: boolean - headerSecret: - type: string - headers: - additionalProperties: - type: string - type: object - method: - type: string - url: - type: string - required: - - events - type: object - type: object - type: array - notificationsTemplate: - type: string - source: - description: VaultClient is a single self-contained vault client - properties: - address: - type: string - authMethod: - type: string - cidr: - type: string - merge: - type: boolean - namespace: - type: string - path: - type: string - role: - type: string - ttl: - type: string - type: object - suspend: - type: boolean - syncDelete: - type: boolean - transforms: - properties: - exclude: - items: - type: string - type: array - include: - items: - type: string - type: array - rename: - items: - properties: - from: - type: string - to: - type: string - required: - - from - - to - type: object - type: array - template: - type: string - type: object - required: - - dest - - source - type: object - status: - description: SecretSyncStatus defines the observed state of SecretSync - properties: - hash: - type: string - lastSyncTime: - format: date-time - type: string - status: - type: string - syncDestinations: - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/NOTES.txt b/deploy/charts/secretsync/charts/secretsync-operator/templates/NOTES.txt deleted file mode 100644 index 48029b1..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/NOTES.txt +++ /dev/null @@ -1,5 +0,0 @@ -The SecretSync Operator has been installed. - -To verify that the operator is running, run: - - kubectl get pods -n {{ .Release.Namespace }} -l "app.kubernetes.io/name=secretsync-operator" \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/_helpers.tpl b/deploy/charts/secretsync/charts/secretsync-operator/templates/_helpers.tpl deleted file mode 100644 index a170261..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/_helpers.tpl +++ /dev/null @@ -1,100 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "secretsync-operator.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "secretsync-operator.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "secretsync-operator.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "secretsync-operator.labels" -}} -helm.sh/chart: {{ include "secretsync-operator.chart" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Common Selector labels -*/}} -{{- define "secretsync-operator.selectorLabels" -}} -app.kubernetes.io/name: {{ include "secretsync-operator.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Operator Selector labels -*/}} -{{- define "secretsync-operator.operatorLabels" -}} -{{ include "secretsync-operator.labels" . }} -{{ include "secretsync-operator.selectorLabels" . }} -app.kubernetes.io/component: operator -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "secretsync-operator.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "secretsync-operator.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} - - -{{/* -Simplify the definition of the kube metrics port -*/}} -{{- define "secretsync-operator.kubeMetricsPort" -}} -{{- if .Values.config.backend }} -{{- default "9080" .Values.config.backend.metricsAddr }} -{{- else }} -{{- "9080" }} -{{- end }} -{{- end }} - -{{/* -Simplify the definition of the event port -*/}} -{{- define "secretsync-operator.metricsPort" -}} -{{- default "9090" .Values.metricsPort }} -{{- end }} - -{{/* -Create the name of the configMap to use -*/}} -{{- define "secretsync-operator.configMapName" -}} -{{- if .Values.existingConfigMap }} -{{- .Values.existingConfigMap -}} -{{- else }} -{{- include "secretsync-operator.fullname" . -}} -{{- end }} -{{- end -}} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml deleted file mode 100644 index 16e4aa4..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrole.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if .Values.rbac.create -}} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "secretsync-operator.fullname" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} -rules: - - apiGroups: [""] - resources: ["events", "secrets", "configmaps"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - - apiGroups: ["secretsync.extendeddata.dev"] - resources: ["secretsyncs"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - - apiGroups: ["secretsync.extendeddata.dev"] - resources: ["secretsyncs/status"] - verbs: ["get", "update", "patch"] -{{- end -}} diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrolebinding.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrolebinding.yaml deleted file mode 100644 index 7f10b16..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/clusterrolebinding.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .Values.rbac.create -}} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "secretsync-operator.fullname" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "secretsync-operator.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ include "secretsync-operator.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- end -}} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/configmap.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/configmap.yaml deleted file mode 100644 index afbb3bd..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/configmap.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if (eq .Values.existingConfigMap "") }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "secretsync-operator.configMapName" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} -data: - config.yaml: | - {{- .Values.config | toYaml | nindent 4 }} -{{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/deployment.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/deployment.yaml deleted file mode 100644 index 090f311..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/deployment.yaml +++ /dev/null @@ -1,95 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "secretsync-operator.fullname" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} - {{- with .Values.deploymentAnnotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "secretsync-operator.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "secretsync-operator.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "secretsync-operator.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - args: - - "-config" - - "/config/config.yaml" - - "-operator" - {{- if .Values.leaderElection.enabled }} - - "-enable-leader-election" - {{- end }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - containerPort: {{ include "secretsync-operator.metricsPort" . }} - name: metrics - livenessProbe: - httpGet: - path: /healthz - port: metrics - readinessProbe: - httpGet: - path: /healthz - port: metrics - {{- with .Values.env }} - env: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.envFrom }} - envFrom: - {{- toYaml . | nindent 12 }} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - name: config - mountPath: /config - readOnly: true - {{- with .Values.extraVolumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: config - configMap: - name: {{ include "secretsync-operator.configMapName" . }} - defaultMode: 420 - optional: true - {{- with .Values.extraVolumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/hpa.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/hpa.yaml deleted file mode 100644 index dad71b8..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "secretsync-operator.fullname" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "secretsync-operator.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deploy/charts/secretsync/charts/secretsync-operator/templates/serviceaccount.yaml b/deploy/charts/secretsync/charts/secretsync-operator/templates/serviceaccount.yaml deleted file mode 100644 index f93ec67..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "secretsync-operator.serviceAccountName" . }} - labels: - {{- include "secretsync-operator.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deploy/charts/secretsync/charts/secretsync-operator/values.yaml b/deploy/charts/secretsync/charts/secretsync-operator/values.yaml deleted file mode 100644 index d59da4b..0000000 --- a/deploy/charts/secretsync/charts/secretsync-operator/values.yaml +++ /dev/null @@ -1,183 +0,0 @@ -# Default values for secretsync-operator. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# the configuration for the operator -existingConfigMap: "" -config: {} - -# Leader election configuration for HA deployments -leaderElection: - enabled: true -# # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# log: -# level: "debug" # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# format: "json" # The format of the log output. Can be one of "json" or "text" -# events: true # Whether to log events. - -# # Configuration for the event server. -# events: -# # Whether the event server is enabled. -# enabled: true -# # The port the event server listens on. -# port: 8080 -# # Security settings for the event server. -# security: -# # Whether security is enabled for the event server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the event server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" -# # Whether to deduplicate events. -# dedupe: true - -# # Configuration for the operator. -# operator: -# # Whether the operator is enabled. -# enabled: true -# workerPoolSize: 10 -# # The number of subscriptions to use. -# numSubscriptions: 10 -# # Backend configuration for the operator. -# backend: -# # The type of backend to use. -# type: "your-backend-type" -# # Parameters for the backend. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the stores. -# stores: - # aws: - # region: "us-west-2" - - # github: - # installId: 12345 - # appId: 67890 - # privateKeyPath: "/path/to/private/key" - -# # Configuration for the queue. -# queue: -# # The type of queue to use. -# type: "your-queue-type" -# # Parameters for the queue. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the metrics server. -# metrics: -# # The port the metrics server listens on. -# port: 9090 -# # Security settings for the metrics server. -# security: -# # Whether security is enabled for the metrics server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the metrics server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" - -# notifications: -# email: -# enabled: true -# host: "smtp.example.com" -# port: 587 -# username: "your-email@example.com" -# password: "your-email-password" -# from: "your-email@example.com" -# to: "recipient@example.com" -# subject: "Notification Subject" -# body: "This is the notification body." -# slack: -# enabled: true -# url: "https://hooks.slack.example.com/services/xxx/xxx/xxx" -# message: "This is the notification message." -# webhook: -# enabled: true -# url: "https://example.com/webhook" -# method: "POST" -# headers: -# Content-Type: "application/json" -# body: | -# { -# "status": "{{ .Status }}", -# "message": "{{ .Message }}" -# } - - - -replicaCount: 1 - -image: - repository: docker.io/jbcom/secretssync - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -rbac: - # Specifies whether RBAC resources should be created - create: true - -deploymentAnnotations: {} -podAnnotations: {} - -podSecurityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - fsGroup: 65534 - -securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 65534 - -resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -env: [] -envFrom: [] -extraVolumeMounts: [] -extraVolumes: [] \ No newline at end of file diff --git a/deploy/charts/secretsync/templates/_helpers.tpl b/deploy/charts/secretsync/templates/_helpers.tpl index a0b3c3e..7f29b11 100644 --- a/deploy/charts/secretsync/templates/_helpers.tpl +++ b/deploy/charts/secretsync/templates/_helpers.tpl @@ -5,17 +5,30 @@ Expand the name of the chart. {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} +{{/* +Create a default fully qualified app name. +*/}} +{{- define "secretsync.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} {{/* Define the name of the configMap. */}} {{- define "secretsync.configMapName" -}} -{{- if .Values.existingConfigMap }} -{{- .Values.existingConfigMap -}} -{{- else if .Values.configMapName }} -{{- .Values.configMapName -}} +{{- if .Values.pipeline.existingConfigMap }} +{{- .Values.pipeline.existingConfigMap -}} {{- else }} -{{- printf "%s-%s" .Chart.Name "config" | trunc 63 | trimSuffix "-" -}} +{{- printf "%s-config" (include "secretsync.fullname" .) | trunc 63 | trimSuffix "-" -}} {{- end }} {{- end -}} @@ -36,4 +49,23 @@ helm.sh/chart: {{ include "secretsync.chart" . }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "secretsync.selectorLabels" -}} +app.kubernetes.io/name: {{ include "secretsync.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use. +*/}} +{{- define "secretsync.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "secretsync.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/charts/secretsync/templates/configmap.yaml b/deploy/charts/secretsync/templates/configmap.yaml index f639efb..75d872c 100644 --- a/deploy/charts/secretsync/templates/configmap.yaml +++ b/deploy/charts/secretsync/templates/configmap.yaml @@ -1,10 +1,12 @@ ---- +{{- if and .Values.pipeline.enabled (not .Values.pipeline.existingConfigMap) }} apiVersion: v1 kind: ConfigMap metadata: name: {{ include "secretsync.configMapName" . }} labels: {{- include "secretsync.labels" . | nindent 4 }} + {{- include "secretsync.selectorLabels" . | nindent 4 }} data: config.yaml: | - {{- .Values.config | toYaml | nindent 4 }} + {{- .Values.pipeline.config | toYaml | nindent 4 }} +{{- end }} diff --git a/deploy/charts/secretsync/templates/cronjob.yaml b/deploy/charts/secretsync/templates/cronjob.yaml new file mode 100644 index 0000000..269dc1d --- /dev/null +++ b/deploy/charts/secretsync/templates/cronjob.yaml @@ -0,0 +1,118 @@ +{{- if .Values.pipeline.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "secretsync.fullname" . }} + labels: + {{- include "secretsync.labels" . | nindent 4 }} + {{- include "secretsync.selectorLabels" . | nindent 4 }} +spec: + schedule: {{ required "pipeline.schedule is required when pipeline.enabled=true" .Values.pipeline.schedule | quote }} + concurrencyPolicy: {{ .Values.pipeline.concurrencyPolicy }} + successfulJobsHistoryLimit: {{ .Values.pipeline.successfulJobsHistoryLimit }} + failedJobsHistoryLimit: {{ .Values.pipeline.failedJobsHistoryLimit }} + jobTemplate: + spec: + backoffLimit: {{ .Values.pipeline.backoffLimit }} + template: + metadata: + labels: + {{- include "secretsync.selectorLabels" . | nindent 12 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + serviceAccountName: {{ include "secretsync.serviceAccountName" . }} + restartPolicy: {{ .Values.pipeline.restartPolicy }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 12 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 12 }} + containers: + - name: secretsync + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + securityContext: + {{- toYaml .Values.securityContext | nindent 16 }} + args: + - pipeline + - --config + - /config/config.yaml + - --continue-on-error={{ .Values.pipeline.continueOnError }} + - --diff={{ .Values.pipeline.diff }} + - --dry-run={{ .Values.pipeline.dryRun }} + - --exit-code={{ .Values.pipeline.exitCode }} + - --output + - {{ .Values.pipeline.output | quote }} + - --parallelism + - {{ .Values.pipeline.parallelism | quote }} + {{- if .Values.pipeline.targets }} + - --targets + - {{ .Values.pipeline.targets | quote }} + {{- end }} + {{- if .Values.pipeline.mergeOnly }} + - --merge-only + {{- end }} + {{- if .Values.pipeline.syncOnly }} + - --sync-only + {{- end }} + {{- if .Values.pipeline.discover }} + - --discover + {{- end }} + {{- if .Values.logLevel }} + - --log-level + - {{ .Values.logLevel | quote }} + {{- end }} + {{- if .Values.logFormat }} + - --log-format + - {{ .Values.logFormat | quote }} + {{- end }} + {{- if .Values.metrics.enabled }} + - --metrics-addr + - {{ .Values.metrics.addr | quote }} + - --metrics-port + - {{ .Values.metrics.port | quote }} + {{- end }} + {{- with .Values.env }} + env: + {{- toYaml . | nindent 16 }} + {{- end }} + {{- with .Values.envFrom }} + envFrom: + {{- toYaml . | nindent 16 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 16 }} + volumeMounts: + - name: config + mountPath: /config + readOnly: true + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 16 }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ include "secretsync.configMapName" . }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 12 }} + {{- end }} +{{- end }} diff --git a/deploy/charts/secretsync/templates/serviceaccount.yaml b/deploy/charts/secretsync/templates/serviceaccount.yaml new file mode 100644 index 0000000..6ba878a --- /dev/null +++ b/deploy/charts/secretsync/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.pipeline.enabled .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "secretsync.serviceAccountName" . }} + labels: + {{- include "secretsync.labels" . | nindent 4 }} + {{- include "secretsync.selectorLabels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/charts/secretsync/values.yaml b/deploy/charts/secretsync/values.yaml index 42cafd1..4e164d6 100644 --- a/deploy/charts/secretsync/values.yaml +++ b/deploy/charts/secretsync/values.yaml @@ -1,329 +1,78 @@ nameOverride: "" - -existingConfigMap: "" -configMapName: secretsync-config - -# Legacy config format (operator mode) -config: {} - -# ============================================================================= -# Pipeline Configuration (NEW) -# ============================================================================= -# Unified pipeline configuration for multi-account secrets management. -# Works identically via CLI, Kubernetes operator, or Helm. -# -# Operations: -# - merge: Source stores → Merge store (with inheritance) -# - sync: Merge store → AWS Secrets Manager -# - pipeline: merge + sync in dependency order +fullnameOverride: "" + +image: + repository: docker.io/jbcom/secretssync + pullPolicy: IfNotPresent + tag: "" + +imagePullSecrets: [] + +serviceAccount: + create: true + annotations: {} + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: + runAsNonRoot: true + runAsUser: 65534 + runAsGroup: 65534 + fsGroup: 65534 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 65534 + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +env: [] +envFrom: [] +extraVolumeMounts: [] +extraVolumes: [] + +nodeSelector: {} +tolerations: [] +affinity: {} + +logLevel: info +logFormat: json + +metrics: + enabled: false + addr: "0.0.0.0" + port: 9090 pipeline: - # Enable pipeline mode (uses new unified config format) enabled: false - - # Pipeline configuration (inline or reference existing ConfigMap) - # existingConfigMap: my-pipeline-config - - config: {} - # Example pipeline configuration: - # config: - # vault: - # address: https://vault.example.com/ - # namespace: eng/data-platform - # auth: - # approle: - # role_id: ${VAULT_ROLE_ID} - # secret_id: ${VAULT_SECRET_ID} - # - # aws: - # region: us-east-1 - # execution_context: - # type: delegated_admin - # account_id: "123456789012" - # control_tower: - # enabled: true - # execution_role: - # name: AWSControlTowerExecution - # - # sources: - # analytics: - # vault: - # mount: analytics - # analytics-engineers: - # vault: - # mount: analytics-engineers - # - # merge_store: - # vault: - # mount: merged-secrets - # - # targets: - # Serverless_Stg: - # account_id: "111111111111" - # imports: - # - analytics - # - analytics-engineers - # Serverless_Prod: - # account_id: "222222222222" - # imports: - # - Serverless_Stg # Inherits from Stg - # - # pipeline: - # merge: - # parallel: 4 - # sync: - # parallel: 4 - # delete_orphans: false - - # Schedule for automatic pipeline runs (cron format) - # Leave empty to disable scheduled runs schedule: "" - # schedule: "0,30 * * * *" # Every 30 minutes - - # Default operation when triggered - operation: pipeline # merge, sync, or pipeline - - # Continue processing even if some targets fail + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 3 + backoffLimit: 1 + restartPolicy: Never + existingConfigMap: "" + config: {} + targets: "" + mergeOnly: false + syncOnly: false + dryRun: false + discover: false continueOnError: true -# # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# log: -# level: "debug" # The log level for the application. Can be one of "debug", "info", "warn", "error", "fatal", or "panic". -# format: "json" # The format of the log output. Can be one of "json" or "text" -# events: true # Whether to log events. - -# # Configuration for the event server. -# events: -# # Whether the event server is enabled. -# enabled: true -# # The port the event server listens on. -# port: 8080 -# # Security settings for the event server. -# security: -# # Whether security is enabled for the event server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the event server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" -# # Whether to deduplicate events. -# dedupe: true - -# # Configuration for the operator. -# operator: -# # Whether the operator is enabled. -# enabled: true -# # Backend configuration for the operator. -# backend: -# # The type of backend to use. -# type: "your-backend-type" -# # Parameters for the backend. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the stores. -# stores: - # aws: - # region: "us-west-2" - - # github: - # installId: 12345 - # appId: 67890 - # privateKeyPath: "/path/to/private/key" - -# # Configuration for the queue. -# queue: -# # The type of queue to use. -# type: "your-queue-type" -# # Parameters for the queue. -# params: -# param1: "value1" -# param2: "value2" - -# # Configuration for the metrics server. -# metrics: -# # The port the metrics server listens on. -# port: 9090 -# # Security settings for the metrics server. -# security: -# # Whether security is enabled for the metrics server. -# enabled: true -# # The token used for authentication. -# token: "your-token" -# # TLS configuration for the metrics server. -# tls: -# certFile: "/path/to/certfile" -# keyFile: "/path/to/keyfile" - -# notifications: -# email: -# enabled: true -# host: "smtp.example.com" -# port: 587 -# username: "your-email@example.com" -# password: "your-email-password" -# from: "your-email@example.com" -# to: "recipient@example.com" -# subject: "Notification Subject" -# body: "This is the notification body." -# slack: -# enabled: true -# url: "https://hooks.slack.example.com/services/xxx/xxx/xxx" -# message: "This is the notification message." -# webhook: -# enabled: true -# url: "https://example.com/webhook" -# method: "POST" -# headers: -# Content-Type: "application/json" -# body: | -# { -# "status": "{{ .Status }}", -# "message": "{{ .Message }}" -# } - - -secretsync-operator: - enabled: true - existingConfigMap: secretsync-config - replicaCount: 1 - - image: - repository: docker.io/jbcom/secretssync - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - - imagePullSecrets: [] - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - - rbac: - # Specifies whether RBAC resources should be created - create: true - - deploymentAnnotations: {} - podAnnotations: {} - - podSecurityContext: - runAsNonRoot: true - runAsUser: 65534 # nobody user - runAsGroup: 65534 - fsGroup: 65534 - - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 65534 - - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 128Mi - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - - nodeSelector: {} - - tolerations: [] - - affinity: {} - - env: [] - envFrom: [] - extraVolumeMounts: [] - extraVolumes: [] - - -secretsync-events: - enabled: true - existingConfigMap: secretsync-config - replicaCount: 1 - - image: - repository: docker.io/jbcom/secretssync - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - - imagePullSecrets: [] - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - - deploymentAnnotations: {} - podAnnotations: {} - - podSecurityContext: {} - # fsGroup: 2000 - - securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - - containerPort: 8080 - - service: - type: ClusterIP - port: 8080 - - resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - - nodeSelector: {} - - tolerations: [] - - affinity: {} - - env: [] - envFrom: [] - extraVolumeMounts: [] - extraVolumes: [] \ No newline at end of file + parallelism: 0 + output: json + diff: true + exitCode: false diff --git a/docs/FAQ.md b/docs/FAQ.md index eadcf67..5ba17da 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -96,17 +96,30 @@ path "secret/metadata/*" { Inheritance allows targets to import configuration from other targets: ```yaml +sources: + common-secrets: + vault: + mount: common + staging-overrides: + vault: + mount: staging + prod-overrides: + vault: + mount: production + targets: base: imports: [common-secrets] staging: - inherits: base # Gets everything from base - imports: [staging-overrides] # Plus staging-specific secrets + imports: + - base + - staging-overrides production: - inherits: staging # Gets base + staging - imports: [prod-overrides] # Plus production-specific secrets + imports: + - staging + - prod-overrides ``` ### Can I sync to multiple AWS accounts? @@ -116,14 +129,16 @@ Yes! Use cross-account IAM roles: ```yaml targets: dev-account: - aws_secretsmanager: - role_arn: "arn:aws:iam::111111111111:role/SecretSyncRole" - region: "us-east-1" + account_id: "111111111111" + role_arn: "arn:aws:iam::111111111111:role/SecretSyncRole" + region: "us-east-1" + imports: [shared-secrets] prod-account: - aws_secretsmanager: - role_arn: "arn:aws:iam::222222222222:role/SecretSyncRole" - region: "us-east-1" + account_id: "222222222222" + role_arn: "arn:aws:iam::222222222222:role/SecretSyncRole" + region: "us-east-1" + imports: [shared-secrets] ``` ### How do I handle different environments? @@ -199,8 +214,9 @@ targets: imports: [base-secrets] production: - inherits: staging # Reads from merge store - imports: [prod-overrides] + imports: + - staging + - prod-overrides ``` ### How does AWS Organizations discovery work? @@ -208,19 +224,23 @@ targets: Automatically discover and sync to accounts based on tags and OUs: ```yaml -discovery: - aws_organizations: - enabled: true - tag_filters: - - key: "Environment" - values: ["production", "staging"] - operator: "equals" - - key: "Team" - values: ["platform*"] - operator: "contains" - organizational_units: - - "ou-production-12345" - tag_logic: "AND" +dynamic_targets: + production_and_staging: + discovery: + organizations: + ous: + - ou-production-12345 + recursive: true + tag_filters: + - key: Environment + values: ["production", "staging"] + operator: equals + - key: Team + values: ["platform*"] + operator: contains + tag_combination: AND + imports: + - shared-secrets ``` ## Operations @@ -339,13 +359,15 @@ Common causes and solutions: 3. **Region mismatch**: ```yaml # Ensure regions match - aws: - region: "us-east-1" - targets: - production: - aws_secretsmanager: - region: "us-east-1" # Must match - ``` + aws: + region: "us-east-1" + targets: + production: + account_id: "222222222222" + region: "us-east-1" + imports: + - shared-secrets + ``` ### "Secret not found in Vault" diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 8881b7c..3c5a7c5 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -75,11 +75,11 @@ the independent SecretSync repository. - **Real-time Monitoring**: Live pipeline execution monitoring - **User Management**: Built-in user authentication and authorization -#### 🔧 Operator Enhancements -- **Kubernetes Operator v2**: Enhanced CRD-based management -- **GitOps Integration**: ArgoCD/Flux integration for configuration management +#### 🔧 Kubernetes Runtime +- **GitOps Examples**: ArgoCD/Flux examples for scheduled pipeline runners - **Helm Chart Improvements**: Advanced deployment options -- **Multi-Cluster Support**: Manage secrets across multiple clusters +- **Multi-Cluster Patterns**: Run scoped pipeline jobs per cluster or account boundary +- **Native API Research**: Evaluate a future controller only if it can be owned end to end #### 🌐 API & Integrations - **REST API**: Full REST API for programmatic access diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 73f052b..6dd2d9c 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -25,24 +25,19 @@ operators and secured log sinks. ### Segregation of Duties -By default, all components of the app default to disabled. This is to ensure that you are only enabling the components you need. To run in "single binary mode", you must explicitly enable each component. This is to ensure that you are aware of the security implications of each component you are enabling. This also enables you to more easily deploy the service in a microservices architecture, where you can run the webhook service in one container and the sync operator in another. - +SecretSync runs as an explicit pipeline command. Split duties by separating +configuration authors, CI/CD approvers, runtime identities, and target account +roles. In Kubernetes, prefer a scheduled job with a dedicated service account +and narrowly scoped projected credentials. ## Security Configuration -### API Server - -The service exposes one API process, the `Event Server` which is responsible for handling audit log events from Vault. - -The API server can be secured either with mTLS, an auth token string, or both. Of course you can also - and are recommended to - further secure communication via service mesh, network policies, or other network security controls. - -If in doubt, it is recommended to use mTLS for all communication with the service. This will ensure that all communication is encrypted and that the client is authenticated. If you are running in a Kubernetes cluster, you can use `cert-manager` to automatically provision certificates for your services. If using token auth, the token must be passed as a `X-Vault-Secret-Sync-Token` header in the request. +### Pipeline Runner -### Queue - -If deployed in HA / microservice mode, the service will rely on a queue to communicate between the `Event Server` and the `Sync Operator`. - -The event server only needs to publish to the queue, and the sync operator only needs to consume from the queue. All appropriate measures should be taken to secure the queue, including network policies, authentication, and encryption. +The supported runtime surface is `secretsync pipeline`. It does not expose an +ingress API by default. Network access should be outbound-only to the configured +secret stores and cloud provider APIs unless your environment adds its own +wrapping service. ### Secret Stores @@ -52,15 +47,22 @@ It is recommended to use a service account with the least privileges necessary t All operations performed by the service include an `X-Vault-Sync: true` header to identify the action as being performed by the sync service. -As the operator itself is effectively `root` for lack of a better analogy, it is critical to ensure that the operator is only deployed in environments where it can be trusted. Furthermore, as the operator will dutifully do what it is told to do, it is critical to ensure proper RBAC and policy is in place around modifying operator and / or sync configurations. If deployed in a Kubernetes cluster, it is recommended to use the Kubernetes native RBAC system to limit access to the operator and sync configurations. +The pipeline runtime is highly privileged relative to the stores it can read +from and write to. Keep configuration changes behind review, protect the merge +store, and scope runtime identities to only the source paths and target accounts +the pipeline needs. Every sync operation will instantiate a new client to the source and destination secret store, and will close the client after the operation is complete. At no time are client objects reused between sync operations. This is to ensure that the client is not left open and vulnerable to attack. #### AWS -If you are running in AWS EKS, you can use IAM roles to grant the operator access to the AWS Secrets Manager. If you are running in a different environment, you can use the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to provide the operator with the necessary credentials. If you are using access keys, it is recommended to rotate these regularly, and utilize a project such as [External Secrets Operator](https://external-secrets.io/latest/) to manage the lifecycle of the access keys into the operator. +If you are running in AWS EKS, use workload identity or IRSA for the pipeline +runner. If you are running in a different environment, you can use +`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, but prefer short-lived +credentials and rotate any static keys regularly. -For cross-account access you must configure an IAM role in your target account which can be assumed by the identity associated with the operator. +For cross-account access you must configure an IAM role in your target account +which can be assumed by the identity associated with the pipeline runner. Your role will need to have the following permissions: @@ -118,47 +120,13 @@ and an example trusted entity configuration: } ``` -#### GCP - -If you are running in GCP GKE, you can use GCP service accounts to grant the operator access to GCP Secret Manager. If you are running in a different environment, you can use the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to provide the operator with the necessary credentials. If you are using service accounts, it is recommended to rotate these regularly, and utilize a project such as [External Secrets Operator](https://external-secrets.io/latest/) to manage the lifecycle of the service account keys into the operator. - -This identity associated with the operator must be granted the following permissions: - -- `secretmanager.versions.access` -- `secretmanager.versions.add` -- `secretmanager.versions.create` -- `secretmanager.versions.destroy` -- `secretmanager.versions.disable` -- `secretmanager.versions.enable` -- `secretmanager.versions.get` -- `secretmanager.versions.list` -- `secretmanager.versions.restore` -- `secretmanager.versions.update` -- `secretmanager.secrets.access` -- `secretmanager.secrets.addVersion` -- `secretmanager.secrets.create` -- `secretmanager.secrets.delete` -- `secretmanager.secrets.get` -- `secretmanager.secrets.list` -- `secretmanager.secrets.update` - -#### GitHub - -GitHub requires a GitHub App installed in the account with access to the level of secrets you desire. When you create your GitHub App, it will have an `installId`, `appId`, and `privateKey`. You will need to provide these to the operator to authenticate with GitHub. It is recommended to rotate the private key regularly, and utilize a project such as [External Secrets Operator](https://external-secrets.io/latest/) to manage the lifecycle of the private key into the operator. - -Heere is an example store configuration: - -```yaml -stores: - github: - installId: 12345 - appId: 67890 - privateKeyPath: "/path/to/private/key" -``` - ### HashiCorp Vault -If you are running in a Kubernetes cluster, you can use the Kubernetes auth method to authenticate the operator with Vault. If you are running in a different environment, you can use the `VAULT_TOKEN` environment variable to provide the operator with the necessary token. If you are using tokens, it is recommended to rotate these regularly, and utilize a project such as [External Secrets Operator](https://external-secrets.io/latest/) to manage the lifecycle of the tokens into the operator. +If you are running in Kubernetes, you can use the Kubernetes auth method to +authenticate the pipeline runner with Vault. If you are running in a different +environment, use AppRole or `VAULT_TOKEN`. Rotate long-lived credentials +regularly and prefer a secret manager or workload identity mechanism to inject +them into the runtime environment. ## Vulnerability Reporting diff --git a/docs/TWO_PHASE_ARCHITECTURE.md b/docs/TWO_PHASE_ARCHITECTURE.md index 91f28a7..d9fb880 100644 --- a/docs/TWO_PHASE_ARCHITECTURE.md +++ b/docs/TWO_PHASE_ARCHITECTURE.md @@ -5,7 +5,7 @@ The secrets synchronization pipeline operates in two distinct phases: 1. **MERGE Phase** (optional): Aggregate secrets from multiple sources into a unified pool -2. **SYNC Phase**: Propagate secrets from source(s) to target(s) +2. **SYNC Phase**: Propagate merged bundles into AWS Secrets Manager targets ``` ┌──────────────────────────────────────────────────────────────────────────────┐ @@ -25,7 +25,7 @@ The secrets synchronization pipeline operates in two distinct phases: │ │ └─────────┘ │ │ • Aggregation │ │ │ │ │ ┌─────────┐ │ │ • Deduplication │ │ │ │ │ │ Source3 │──┘ │ • Inheritance │ │ │ -│ │ │ (HTTP) │ │ • DeepMerge │ │ │ +│ │ │ (Vault) │ │ • DeepMerge │ │ │ │ │ └─────────┘ └────────┬─────────┘ │ │ │ │ │ │ │ │ └───────────────────────────────┼──────────────────────────────────────┘ │ @@ -40,10 +40,10 @@ The secrets synchronization pipeline operates in two distinct phases: │ │ │ SOURCE │────▶│ Target1 (AWS) │ │ │ │ │ │ (Merge Store │ └─────────────────┘ │ │ │ │ │ or Direct) │ ┌─────────────────┐ │ │ -│ │ │ │────▶│ Target2 (Vault)│ │ │ +│ │ │ │────▶│ Target2 (AWS) │ │ │ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ ┌─────────────────┐ │ │ -│ │ │ │────▶│ Target3 (GCP) │ │ │ +│ │ │ │────▶│ Target3 (AWS) │ │ │ │ │ └──────────────────┘ └─────────────────┘ │ │ │ │ │ │ │ └───────────────────────────────────────────────────────────────────────┘ │ @@ -84,23 +84,19 @@ For each target in topological order: ### SYNC Phase -**Purpose**: Propagate secrets from source to target stores. +**Purpose**: Propagate merged secrets into AWS Secrets Manager targets. **Source determination**: - If MERGE phase ran: Merge store becomes the source automatically - If SYNC-only: Explicitly configured source **Supported Store Combinations**: -| Source | Target | Status | -|--------|--------|--------| -| Vault | AWS Secrets Manager | ✅ Supported | -| Vault | Vault | ✅ Supported | -| Vault | GCP Secret Manager | ✅ Supported | -| Vault | GitHub Secrets | ✅ Supported | -| Vault | Kubernetes Secrets | ✅ Supported | -| AWS SM | AWS SM | ✅ Supported | -| AWS SM | Vault | ✅ Supported | -| S3 | AWS SM | ✅ Supported (via S3 merge store) | +| Source or Merge Store | Target | Status | +|-----------------------|--------|--------| +| Vault KV2 | AWS Secrets Manager | ✅ Supported | +| AWS Secrets Manager | AWS Secrets Manager | ✅ Supported | +| Vault merge store | AWS Secrets Manager | ✅ Supported | +| S3 merge store | AWS Secrets Manager | ✅ Supported | **Sync Process**: ``` @@ -276,12 +272,14 @@ targets: imports: [common-secrets] Staging: - inherits: Base - imports: [staging-secrets] + imports: + - Base + - staging-secrets Production: - inherits: Staging - imports: [production-secrets] + imports: + - Staging + - production-secrets ``` **Processing Order**: diff --git a/docs/USAGE.md b/docs/USAGE.md index 089720d..1cf78bf 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -1,297 +1,131 @@ # Usage -## YAML Configuration +SecretSync is a pipeline runner. It reads configured sources, merges secret +material into a merge store, and syncs the resulting bundles into AWS Secrets +Manager targets. -```yaml -apiVersion: secretsync.extendeddata.dev/v1alpha1 -kind: SecretSync -metadata: - name: "example-sync" - namespace: "default" -spec: - dryRun: false - syncDelete: false - suspend: false - source: - address: "https://vault.example.com" - path: "foo/bar/(.*)" - namespace: "platform/secrets" - filters: - regex: - include: - - "foo/bar/hello-[0-9]+" - exclude: - - "foo/bar/no[^abc]+" - paths: - include: - - "foo/bar/hello" - exclude: - - "foo/bar/no" - dest: - - vault: - address: "https://vault2.example.com" - path: "hello/world/$1" - namespace: "platform/secrets" - - vault: - address: "https://vault3.example.com" - path: "another/vault" - - aws: - name: "example-secret" - region: "us-west-2" - roleArn: "arn:aws:iam::123456789012:role/role-name" - encryptionKey: "alias/aws/secretsmanager" - replicaRegions: ["us-east-1"] - - github: - repo: "example-repo" - owner: "platform-team" - - gcp: - project: "example-project" - name: "example-secret" - - http: - url: "https://example.com/my/app" - method: "POST" - headerSecret: "default/header-secret" - headers: - Content-Type: "application/json" - template: | - { - "custom": { - "{{ .Key }}": "{{ .Value }}" - } - } - webhooks: - - event: success - url: "https://example.com/success" - method: "POST" - headers: - Content-Type: "application/json" - template: | - { - "custom": { - "event": "{{ .Event }}", - "message": "{{ .Message }}", - "name": "{{ .SecretSync.Name }}" - "source.address": "{{ .SecretSync.Spec.Source.Address }}" - } - } - - event: failure - url: "https://example.com/failure" - method: "POST" - headers: - Content-Type: "application/json" - template: | - { - "custom": { - "event": "{{ .Event }}", - "message": "{{ .Message }}", - "name": "{{ .SecretSync.Name }}" - "source.address": "{{ .SecretSync.Spec.Source.Address }}" - } - } -``` - -`metadata` is that can be used to identify the sync operation. Both can be ommitted, however if `name` is omitted, to trigger a manual sync you will first need to authenticate and access the `/configs` endpoint to get the auto-generated name for your respective config. - -`spec.source` and `spec.dest` are the source and destination of the sync operation. - -`authMethod` and `role` can be omitted to use the default global method and role, if defined. If they are specified, they will be used to authenticate to the Vault instance. Optionally, `token` can be provided as a mustache template referencing an environment variable. If provided, this will always override configured auth methods. - -`path` can either be provided as a path to a single vault kv secret, or as a regex string. If regex, all matching child secrets will be synced. Wildcarding will recurse into child paths, so `foo/test/(.*)` will sync `foo/test/foo` and `foo/test/foo/bar`, but not `foo/test2/foo`. However `foo/test(.*)` will sync `foo/test` and `foo/test2`. You can also use capture groups to rewrite the path in the destination. For example, `foo/(test)/(bar)` will sync `foo/test/bar` and rewrite it to `test/bar` in the destination. - -If you set `source.cidr` to the CIDR in which the source vault is deployed (as seen from ingestion point - so if this is a public Vault, this will be the outbound NAT/IGW), it will enable multiple source vaults to sync through a single instance of the operator. You can also set `x-vault-tenant` header in the log shipping config to specify the source vault from which that log is coming from. - -### Source Determination - -By default, the Vault Audit log contains no contextual information about what Vault it is coming from. To enable this operator to connect to multiple vaults, multi-tenant source determination logic is used based on the following order of precendence. - -- `X-Vault-Tenant` Header: If an `x-vault-tenant` header is set to a Vault URL (as defined in the example fluentd config below), this will be used to perform an exact lookup against configured Vault Source Addresses. -- `X-Forwarded-For` Header: If an `x-forwarded-for` header is set (and the `x-vault-tenant` is not), the operator will perform a source lookup by finding the `source.cidr` which contains the caller IP. -- `Remote IP Address`: If both the `x-vault-tenant` and `x-forwarded-for` headers do not exist, the operator will use the caller's IP address and will perform a source lookup by finding the `source.cidr` which contains the caller IP. - - -### Filters - -Filters can be applied to the sync to include or exclude secrets based on either a regex pattern or a path pattern. The path filter is an explicit match, while the regex filter is a regex pattern match. If both filters are present, the secret must match both filters to be included in the sync. - -```yaml - filters: - regex: - include: - - "foo/bar/hello-[0-9]+" - exclude: - - "foo/bar/no[^abc]+" - paths: - include: - - "foo/bar/hello" - exclude: - - "foo/bar/no" -``` - - -### Destination Configuration - -The destination is configured in the same way as the source, with the exception that the `driver` field can be specified. If no driver is specified, the default driver is `vault`. - -#### Vault (Driver: `vault`) - -The Vault destination driver will write the secret to the target Vault instance. - -```yaml - dest: - - vault: - address: "https://vault.example.com" - path: "foo/test2/(.*)" - namespace: "" - authMethod: "" - role: "" - ttl: 1m # optional, defaults to token default lease time - merge: false # optional, default false. false will overwrite existing secrets with values from vault, merge will merge the two, overwriting only the keys that are present in the new secret -``` +## Configuration -#### GitHub (Driver: `github`) - -The GitHub destination driver will write the secret to a GitHub repository or organization. - -```yaml - dest: - - github: - repo: "example-repo" - env: "" # optional, default empty. Set to a specific environment to sync to within a repo if needed - owner: "platform-team" # optional, will default to the company org - org: false # optional, default false. set to true to set org secret rather than repo secret - merge: false # optional, default true. false will overwrite existing secrets with values from vault, merge will merge the two -``` - -Note that since GitHub secrets do not have a concept of pathing, if you are syncing a wildcard source path, the secrets will be overwritten in the destination repository with a last-write-wins strategy. - -#### AWS Secrets Manager (Driver: `aws`) - -The AWS destination driver will write the secret to AWS Secrets Manager. +Use the current pipeline configuration shape: ```yaml - dest: - - aws: - name: "example-secret" - region: "us-west-2" # optional, default us-east-1 - roleArn: "arn:aws:iam::123456789012:role/role-name" # optional, default empty. Set to a specific role to assume when writing to secrets manager - encryptionKey: "alias/aws/secretsmanager" # optional, default empty. Set to a specific KMS key to use for encryption - replicaRegions: [] # optional, default empty. Set to a list of regions to replicate the secret to +vault: + address: https://vault.example.com/ + namespace: platform/secrets + auth: + approle: + mount: approle + role_id: ${VAULT_ROLE_ID} + secret_id: ${VAULT_SECRET_ID} + +aws: + region: us-east-1 + +sources: + shared: + vault: + mount: shared + paths: + - app/* + production-overrides: + vault: + mount: production + +merge_store: + s3: + bucket: secretsync-merge-store + prefix: merged/ + kms_key_id: alias/secretsync-merge-store + +targets: + staging: + account_id: "111111111111" + region: us-east-1 + secret_prefix: /staging/ + imports: + - shared + production: + account_id: "222222222222" + region: us-east-1 + secret_prefix: /production/ + imports: + - staging + - production-overrides + +dynamic_targets: + analytics_sandboxes: + discovery: + organizations: + ous: + - ou-xxxx-sandbox + recursive: true + tag_filters: + - key: Team + values: + - analytics + operator: equals + imports: + - shared + secret_prefix: /sandbox/ + +pipeline: + merge: + parallel: 4 + sync: + parallel: 4 + delete_orphans: false + dry_run: false + continue_on_error: true ``` -#### GCP Secret Manager (Driver: `gcp`) +`sources` define where secrets are read from. `merge_store` defines the +intermediate bundle store. `targets` define AWS accounts and the source or +target imports that feed them. A target imports another target by listing that +target name in `imports`. -The GCP destination driver will write the secret to GCP Secret Manager in the specified project. +## Validate -```yaml - dest: - - gcp: - project: "example-project" - name: "example-secret" - replicationLocations: [] # optional, default empty. Set to a list of regions to replicate the secret to. If empty, all regions will be used +```bash +secretsync validate --config config.yaml ``` +Validation checks required targets, account ID formats, merge store settings, +dynamic discovery settings, and target inheritance cycles. -Note that since GCP Secret Manager does not support the `/` character, the sync operator will replace `/` with `-` in the secret name. This generally only applies when using a wildcard source path. - - - -#### HTTP (Driver: `http`) +## Plan -The HTTP destination driver will make an HTTP request to the specified URL with the secret data as the body of the request. By default this will be a POST request with a JSON body, but the method, headers, and body can be customized. Note that this will be sending your secrets in plain text to the specified URL, so ensure that the destination is within your control and secure. - -```yaml - dest: - - http: - url: "https://example.com/my/app" - method: "POST" # optional, default POST. Set to the HTTP method to use for the request - headerSecret: "default/header-secret" # optional, default empty. Set to the name of a kubernetes secret in the format namespace/name to use as the header KV pairs for the request - headers: # optional, default empty. Set to a map of headers to include in the request - Content-Type: "application/json" - template: | # optional, default empty. Set to a template to use for the request body. The template is a Go template with the following variables available: .Key, .Value, .Namespace, .Path, .Secret, .Timestamp - { - "custom": { - "{{ .Key }}": "{{ .Value }}" - } - } +```bash +secretsync pipeline --config config.yaml --dry-run --diff --output json ``` -#### Webhooks +Dry runs load the same configuration and compute the same target graph as an +apply run, but skip writes to destination stores. -Webhooks can be configured to send a POST request to a specified URL when a sync event occurs. The event can be either `success` or `failure`, and the request will include a JSON body with information about the event. The template can be customized to include any information from the sync event. +## Apply -```yaml - webhooks: - - event: success - url: "https://example.com/success" - method: "POST" # optional, default POST. Set to the HTTP method to use for the request - headers: # optional, default empty. Set to a map of headers to include in the request - Content-Type: "application/json" - template: | # optional, default empty. Set to a template to use for the request body. The template is a Go template with the following variables available: .Event, .Message, .SecretSync - { - "custom": { - "event": "{{ .Event }}", - "message": "{{ .Message }}", - "name": "{{ .SecretSync.Name }}" - "source.address": "{{ .SecretSync.Spec.Source.Address }}" - } - } - - event: failure - url: "https://example.com/failure" - method: "POST" # optional, default POST. Set to the HTTP method to use for the request - headers: # optional, default empty. Set to a map of headers to include in the request - Content-Type: "application/json" - template: | # optional, default empty. Set to a template to use for the request body. The template is a Go template with the following variables available: .Event, .Message, .SecretSync - { - "custom": { - "event": "{{ .Event }}", - "message": "{{ .Message }}", - "name": "{{ .SecretSync.Name }}" - "source.address": "{{ .SecretSync.Spec.Source.Address }}" - } - } +```bash +secretsync pipeline --config config.yaml --diff --output human ``` -## Operations - -### Kubernetes +Use `--targets staging,production` to limit a run to selected targets and their +dependencies. Use `--merge-only` or `--sync-only` when an operational workflow +needs to split the two phases. -When deployed in Kubernetes, `SecretSync` operations are exposed through the Kubernetes API. `SecretSync` resources can be created, updated, and deleted through the Kubernetes API. - -```yaml -cat < Date: Wed, 10 Jun 2026 16:21:35 -0500 Subject: [PATCH 31/42] docs: align python integration with cli contract --- README.md | 39 +++++++++++------- docs/PYTHON_BINDINGS.md | 89 ++++++++++++++++++++--------------------- docs_markdown_test.go | 49 +++++++++++++++++++++++ 3 files changed, 117 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 92750b6..324ecdd 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![GitHub release](https://img.shields.io/github/release/jbcom/secrets-sync.svg)](https://github.com/jbcom/secrets-sync/releases) [![Go Report Card](https://goreportcard.com/badge/github.com/jbcom/secrets-sync)](https://goreportcard.com/report/github.com/jbcom/secrets-sync) -[![Python Bindings](https://img.shields.io/badge/python-bindings-blue.svg)](./python/) +[![Python Integration](https://img.shields.io/badge/python-integration-blue.svg)](./docs/PYTHON_BINDINGS.md) -[Quick Start](#quick-start) • [Repo Docs](./docs/) • [Python Bindings](#python-bindings) • [Examples](./examples/) • [GitHub Action](./docs/GITHUB_ACTIONS.md) +[Quick Start](#quick-start) • [Repo Docs](./docs/) • [Python Integration](#python-integration) • [Examples](./examples/) • [GitHub Action](./docs/GITHUB_ACTIONS.md) @@ -22,7 +22,11 @@ SecretSync provides **fully automated, enterprise-grade secret synchronization** SecretSync is an independent [jbcom/secrets-sync](https://github.com/jbcom/secrets-sync) repository and MIT-licensed release artifact for secret synchronization workflows. -**🐍 Python Integration**: SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with the [extended-data](https://github.com/jbcom/extended-data) Python package and Python-based AI agents. +**🐍 Python Integration**: SecretSync is available to Python through the +[extended-data](https://github.com/jbcom/extended-data) `extended-data[secrets]` +connector, which executes the supported `secretsync` CLI contract. This repo +also keeps direct [gopy](https://github.com/go-python/gopy) binding sources for +local experiments. **🚀 Perfect for:** Multi-account AWS environments, Kubernetes deployments, CI/CD pipelines, and enterprise secret management at scale. @@ -125,9 +129,15 @@ cd secrets-sync make build ``` -## Python Bindings +## Python Integration -SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling integration with Python applications and AI agent frameworks. +The recommended Python surface is the `extended-data[secrets]` connector. It +uses the `secretsync` CLI and returns mapping-style `ExtendedDict` payloads from +configuration, dry-run, merge, sync, and full pipeline operations. + +The repository also includes direct gopy binding sources under `python/` for +local binding experiments. Those bindings are not the runtime contract used by +`extended-data`. ### Building Python Bindings @@ -153,8 +163,7 @@ pip install extended-data[secrets] ``` This installs the Python connector surface. To execute the full pipeline from -Python, make sure the `secretsync` CLI is installed or the native bindings have -been built in the current environment. +Python, make sure the `secretsync` CLI is installed and available on `PATH`. ```python from extended_data.secrets import SecretsConnector @@ -163,19 +172,21 @@ from extended_data.secrets import SecretsConnector connector = SecretsConnector() # Validate configuration -is_valid, message = connector.validate_config("pipeline.yaml") +validation = connector.validate_config("pipeline.yaml") +if not validation["valid"]: + raise SystemExit(validation["message"]) # Dry run to see what would change result = connector.dry_run("pipeline.yaml") -print(f"Would sync {result.secrets_processed} secrets") -print(f" Add: {result.secrets_added}") -print(f" Modify: {result.secrets_modified}") -print(f" Remove: {result.secrets_removed}") +print(f"Would sync {result['secrets_processed']} secrets") +print(f" Add: {result['secrets_added']}") +print(f" Modify: {result['secrets_modified']}") +print(f" Remove: {result['secrets_removed']}") # Execute the full pipeline result = connector.run_pipeline("pipeline.yaml") -if result.success: - print(f"Successfully synced {result.secrets_added} secrets") +if result["success"]: + print(f"Successfully synced {result['secrets_added']} secrets") ``` ### AI Agent Integration diff --git a/docs/PYTHON_BINDINGS.md b/docs/PYTHON_BINDINGS.md index 36716db..02015b3 100644 --- a/docs/PYTHON_BINDINGS.md +++ b/docs/PYTHON_BINDINGS.md @@ -1,10 +1,17 @@ -# Python Bindings +# Python Integration -SecretSync provides Python bindings via [gopy](https://github.com/go-python/gopy), enabling seamless integration with Python applications, AI agents, and the `extended-data` Python package. +SecretSync is available to Python through the `extended-data[secrets]` +connector. That connector executes the supported `secretsync` CLI contract and +returns mapping-style `ExtendedDict` payloads for configuration inspection, +dry-run, merge, sync, and full pipeline operations. + +This repository also includes direct [gopy](https://github.com/go-python/gopy) +binding sources under `python/` for local experiments. Those bindings are not +the runtime adapter contract used by `extended-data`. ## Overview -The Python bindings expose the core SecretSync functionality: +The `extended-data` connector exposes the core SecretSync functionality: - **Pipeline execution**: Run merge, sync, or full pipeline operations - **Configuration validation**: Validate YAML configuration files @@ -22,17 +29,17 @@ pip install extended-data[secrets] ``` This provides: -- Native bindings when available (fastest) -- CLI fallback when bindings aren't installed +- CLI execution through the stable `secretsync` command +- Mapping-style `ExtendedDict` results - AI framework integrations (LangChain, CrewAI, Strands) - MCP server support To execute the full pipeline from Python, keep the `secretsync` CLI installed -or build the native bindings in the current environment. +and available on `PATH`. -### Option 2: Build Native Bindings +### Option 2: Build Direct gopy Bindings -For maximum performance, build the native Python bindings: +For local experiments with direct Go-to-Python bindings: ```bash # Prerequisites @@ -47,17 +54,17 @@ make python-bindings make python-install ``` -### Option 3: CLI-only Mode +### CLI Requirement -If you have the `secretsync` CLI installed, the Python connector will use it automatically: +The `extended-data` connector requires the `secretsync` CLI: ```bash go install github.com/jbcom/secrets-sync/cmd/secretsync@latest pip install extended-data[secrets] ``` -CLI fallback mode relies on `secretsync pipeline --output json`, which emits -the same stable result envelope for dry-run and apply runs. Diff data is nested +The connector relies on `secretsync pipeline --output json`, which emits the +same stable result envelope for dry-run and apply runs. Diff data is nested under `diff` and `diff_output` when diff computation is enabled. ## Usage @@ -70,19 +77,18 @@ from extended_data.secrets import SecretsConnector # Initialize connector connector = SecretsConnector() -# Check which mode is active -print(f"Native bindings: {connector.native_available}") +# Check that the CLI can be found print(f"CLI available: {connector.cli_available}") # Validate a configuration file -is_valid, message = connector.validate_config("pipeline.yaml") -if not is_valid: - print(f"Invalid config: {message}") +validation = connector.validate_config("pipeline.yaml") +if not validation["valid"]: + print(f"Invalid config: {validation['message']}") # Get configuration info info = connector.get_config_info("pipeline.yaml") -print(f"Sources: {info.sources}") -print(f"Targets: {info.targets}") +print(f"Sources: {info['sources']}") +print(f"Targets: {info['targets']}") ``` ### Dry Run @@ -95,16 +101,16 @@ from extended_data.secrets import SecretsConnector connector = SecretsConnector() result = connector.dry_run("pipeline.yaml") -print(f"Would process {result.target_count} targets") -print(f" Secrets to add: {result.secrets_added}") -print(f" Secrets to modify: {result.secrets_modified}") -print(f" Secrets to remove: {result.secrets_removed}") -print(f" Unchanged: {result.secrets_unchanged}") +print(f"Would process {result['target_count']} targets") +print(f" Secrets to add: {result['secrets_added']}") +print(f" Secrets to modify: {result['secrets_modified']}") +print(f" Secrets to remove: {result['secrets_removed']}") +print(f" Unchanged: {result['secrets_unchanged']}") -# View the diff output -if result.diff_output: - print("\nDiff:") - print(result.diff_output) +# Diff output may contain secret values. Inspect it only in a secure terminal +# or through a redacted reporting path. +if result["diff_output"]: + print("Diff output returned; not printing it from the example.") ``` ### Running the Pipeline @@ -130,10 +136,10 @@ options = SyncOptions( ) result = connector.run_pipeline("pipeline.yaml", options) -if result.success: - print(f"Synced {result.secrets_added} secrets in {result.duration_ms}ms") +if result["success"]: + print(f"Synced {result['secrets_added']} secrets in {result['duration_ms']}ms") else: - print(f"Error: {result.error_message}") + print("Pipeline failed. Re-run secretsync directly in a secure terminal for diagnostics.") ``` ### Merge and Sync Phases @@ -230,33 +236,24 @@ Configure in your MCP client: } ``` -## Performance - -| Mode | Relative Speed | Use Case | -|------|----------------|----------| -| Native bindings | 1x (fastest) | Production workloads | -| CLI subprocess | ~2-5x slower | Development and local fallback | - -The connector automatically uses native bindings when available. - ## Error Handling ```python -from extended_data.secrets import SecretsConnector, SyncResult +from extended_data.secrets import SecretsConnector connector = SecretsConnector() result = connector.run_pipeline("pipeline.yaml") -if not result.success: - print(f"Pipeline failed: {result.error_message}") +if not result["success"]: + print("Pipeline failed. Re-run secretsync directly in a secure terminal for diagnostics.") # Check detailed results import json - if result.results_json: - details = json.loads(result.results_json) + if result["results_json"]: + details = json.loads(result["results_json"]) for target_result in details: if not target_result.get("success"): - print(f" {target_result['target']}: {target_result.get('error')}") + print(f" {target_result['target']}: failed") ``` ## Environment Variables diff --git a/docs_markdown_test.go b/docs_markdown_test.go index faff05b..2045b4c 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -3,6 +3,7 @@ package secretsync_test import ( "os" "path/filepath" + "regexp" "strings" "testing" ) @@ -104,3 +105,51 @@ func TestGettingStartedUsesCurrentPipelineConfigShape(t *testing.T) { } } } + +func TestPythonDocsUseExtendedDataCLIContract(t *testing.T) { + attributeStyleResult := regexp.MustCompile(`\bresult\.`) + paths := []string{"README.md", "docs/PYTHON_BINDINGS.md"} + forbidden := []string{ + "native_available", + "Native bindings", + "native bindings", + "CLI fallback", + "bindings aren't installed", + "is_valid, message", + "print(result[\"diff_output\"])", + } + + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + text := string(content) + + for _, phrase := range forbidden { + if strings.Contains(text, phrase) { + t.Fatalf("%s should not document stale Python integration surface %q", path, phrase) + } + } + if attributeStyleResult.MatchString(text) { + t.Fatalf("%s should use mapping-style result access, not result.attribute examples", path) + } + } + + content, err := os.ReadFile("docs/PYTHON_BINDINGS.md") + if err != nil { + t.Fatalf("read docs/PYTHON_BINDINGS.md: %v", err) + } + text := string(content) + for _, required := range []string{ + "connector.cli_available", + "validation = connector.validate_config", + "result[\"success\"]", + "result['secrets_added']", + "secretsync pipeline --output json", + } { + if !strings.Contains(text, required) { + t.Fatalf("docs/PYTHON_BINDINGS.md should document current Python contract %q", required) + } + } +} From 9c9bb0928f2f468f99236b7b0083decbcd3fed46 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 16:26:11 -0500 Subject: [PATCH 32/42] docs: replace stale operator architecture --- docs/ARCHITECTURE.md | 92 ++++++++++++++++-- docs/architecture/HLA-microservice.drawio | 87 ----------------- docs/architecture/HLA-microservice.drawio.png | Bin 462488 -> 0 bytes docs/architecture/HLA.drawio | 81 --------------- docs/architecture/HLA.drawio.png | Bin 256817 -> 0 bytes docs_markdown_test.go | 44 ++++++--- helm_chart_test.go | 1 - 7 files changed, 115 insertions(+), 190 deletions(-) delete mode 100644 docs/architecture/HLA-microservice.drawio delete mode 100644 docs/architecture/HLA-microservice.drawio.png delete mode 100644 docs/architecture/HLA.drawio delete mode 100644 docs/architecture/HLA.drawio.png diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a9611a0..dcee828 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,23 +1,95 @@ # Architecture -## High Level Architecture +SecretSync is a pipeline runner. The supported runtime is the `secretsync` CLI +executing a configured merge, sync, or full pipeline operation. Kubernetes and +GitHub Actions deployments wrap that same CLI contract instead of introducing a +separate controller API. -![High Level Architecture](./architecture/HLA.drawio.png) +## Runtime Shape -Before we discuss how to technically deploy the solution, it is important to understand the high-level architecture of the service. The above reference architecture can be viewed as a "logical" architecture, as the service can be deployed in a variety of ways. Conceptually, the operator exposes a REST webhook endpoint at `/events` that listens for HashiCorp Vault audit log events. When an event is received, the operator will evaluate it against the configured `SecretSync` resources and sync the secret to the respective destination secret store(s). +```text +pipeline.yaml + | + v +secretsync pipeline --config pipeline.yaml + | + +--> merge phase: source secrets -> merge store + | + +--> sync phase: merged/source secrets -> target stores + | + +--> result envelope: success, counts, per-target results, optional diff +``` -In the most basic deployment model, the operator can be deployed as a single process / docker container / pod. In this mode, the container both exposes the webhook server as well as performs the actual sync operation. This may not be ideal for a more security-conscious environment, as the exposed webhook service would need to be granted access to the backend secret stores and therefore could be a potential attack vector. For this reason, it is generally recommended to deploy the solution as a set of decoupled microservices, where the webhook service is deployed in a separate container / pod from the sync operator. This then allows you to enforce more strict network policies and security controls around the webhook service which then queues the work to be consumed by the operator service deeper in the network. +The pipeline reads one YAML configuration file, resolves source and target +inheritance, optionally writes a merge store, then syncs destination stores. The +same command can run a dry-run with diff output, a merge-only operation, a +sync-only operation, or the full merge-plus-sync pipeline. + +## Core Components + +- **CLI entrypoint**: `cmd/secretsync` exposes `validate`, `pipeline`, and + graph-related commands for local, CI, and scheduled execution. +- **Pipeline package**: `pkg/pipeline` owns config loading, validation, + inheritance resolution, discovery, merge, sync, diff integration, and result + envelopes. +- **Diff package**: `pkg/diff` builds masked human, JSON, GitHub Actions, + compact, and side-by-side diff output. +- **Observability package**: `pkg/observability` exposes metrics for pipeline + runs that opt into the metrics endpoint. +- **GitHub Action**: `action.yml` packages the CLI contract for CI/CD workflows. +- **Helm chart**: the chart renders a Kubernetes `CronJob` plus ConfigMap or + existing config mount for scheduled pipeline execution. +- **Python integration**: `extended-data[secrets]` calls the supported CLI and + consumes the JSON result envelope as mapping-style Python data. ## Deployment Models -While this documentation generally focuses on Kubernetes-based deployments, do know that the service is not coupled to Kubernetes and therefore the same models discussed below can be followed to deploy the service in other environments, either as a set of docker containers, standalone processes, or a single binary. +### Local Or CI Execution + +Run the CLI directly when an operator or engineer controls the execution +environment: + +```bash +secretsync validate --config pipeline.yaml +secretsync pipeline --config pipeline.yaml --dry-run --diff --output json +secretsync pipeline --config pipeline.yaml --output json +``` + +GitHub Actions uses the same contract through the published action. The action +does not own a separate API surface; it validates inputs, executes the pipeline, +and reports outputs suitable for CI workflows. + +### Kubernetes Scheduled Execution + +For Kubernetes, run SecretSync as a `CronJob`. Mount the pipeline configuration +from a ConfigMap or Secret and provide cloud credentials through the cluster +identity model. + +```text +kind: CronJob + -> Pod + -> secretsync pipeline --config /config/config.yaml + -> Vault / AWS Secrets Manager / S3 / AWS discovery APIs +``` + +The Helm chart is intentionally a runner chart. It should not grow a custom +resource, reconciler, or sidecar service unless those components are owned as a +new public runtime contract. -### Single Binary +## Integration Boundaries -The simplest deployment model is to deploy the service as a single binary, as shown in the High Level Diagram above. This is the easiest way to get started with the service, but is not recommended for production deployments. In this model, the service will run as a single process that both listens for webhook events and performs the sync operation. The upside of this model is the ease of deployment, however the downside is that you must grant the exposed webhook service access to the backend secret stores, which may not be ideal from a security perspective. +SecretSync owns the Go CLI, pipeline packages, release artifact, Docker action, +and Helm runner chart. Python applications should use the `extended-data` +connector unless they are explicitly experimenting with the local gopy binding +sources in this repository. -### Microservices +The stable cross-language contract is: -The recommended deployment model is to decouple the microservices and rely on a queue to provide inter-service communication. In this model, the webhook service is deployed as a separate process / container / pod from the sync operator. The webhook service listens for audit log events, filters out irrelevant events, and then queues the relevant events to be consumed by the sync operator. The sync operator then runs in a separate process / container / pod and consumes the queued events, syncing the secrets to the destination secret store(s). In this model, the webhook service only needs to be granted limited access to the queue, and the sync operator only needs to be granted access to the destination secret store(s). Besides the optional Kubernetes metrics endpoint, the sync operator does not expose any other services, and all communication is done through the queue. +```bash +secretsync pipeline --config pipeline.yaml --output json +``` -![Microservices Deployment](./architecture/HLA-microservice.drawio.png) \ No newline at end of file +The JSON result envelope contains pipeline success, target count, secret change +counts, duration, per-target results, and optional diff output. Consumers should +treat diff and error fields as potentially sensitive and redact or suppress +them before writing logs, CI comments, or chat responses. diff --git a/docs/architecture/HLA-microservice.drawio b/docs/architecture/HLA-microservice.drawio deleted file mode 100644 index a155410..0000000 --- a/docs/architecture/HLA-microservice.drawio +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/architecture/HLA-microservice.drawio.png b/docs/architecture/HLA-microservice.drawio.png deleted file mode 100644 index 6cf5f645737991bd4184d0ab79a00d78ac3201f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462488 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 z 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/architecture/HLA.drawio.png b/docs/architecture/HLA.drawio.png deleted file mode 100644 index 2de24a9df8fc3029ed3ebe353b7c07fc929a1e29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256817 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

`s8VM>(;G5?J<4m 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Ⓢ?avZ3j`KB`0cj?gf+)s^( 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 LnnJ#uiQoSL6EU}M diff --git a/docs_markdown_test.go b/docs_markdown_test.go index 2045b4c..60a3dad 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -38,24 +38,32 @@ func TestMarkdownFencedCodeBlocksAreBalanced(t *testing.T) { } func TestDeploymentGuideUsesCurrentPipelineSurface(t *testing.T) { - content, err := os.ReadFile("docs/DEPLOYMENT.md") - if err != nil { - t.Fatalf("read docs/DEPLOYMENT.md: %v", err) - } - - text := string(content) + paths := []string{"docs/ARCHITECTURE.md", "docs/DEPLOYMENT.md"} for _, required := range []string{ "secretsync pipeline", "--dry-run", "--diff", "--output json", "kind: CronJob", - "jbcom/secrets-sync@secrets-sync-vX.Y.Z", } { - if !strings.Contains(text, required) { - t.Fatalf("docs/DEPLOYMENT.md should document current deployment surface %q", required) + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + if !strings.Contains(string(content), required) { + t.Fatalf("%s should document current deployment surface %q", path, required) + } } } + deploymentGuide, err := os.ReadFile("docs/DEPLOYMENT.md") + if err != nil { + t.Fatalf("read docs/DEPLOYMENT.md: %v", err) + } + if !strings.Contains(string(deploymentGuide), "jbcom/secrets-sync@secrets-sync-vX.Y.Z") { + t.Fatal("docs/DEPLOYMENT.md should document the GitHub Action release tag") + } + for _, forbidden := range []string{ "Vault Secrets Sync service", "Event Server", @@ -64,13 +72,27 @@ func TestDeploymentGuideUsesCurrentPipelineSurface(t *testing.T) { "-events", "memory queue", "microservices mode", + "REST webhook endpoint", + "SecretSync resources", } { - if strings.Contains(text, forbidden) { - t.Fatalf("docs/DEPLOYMENT.md should not document stale deployment surface %q", forbidden) + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + if strings.Contains(string(content), forbidden) { + t.Fatalf("%s should not document stale deployment surface %q", path, forbidden) + } } } } +func TestStaleArchitectureDiagramsAreNotPublished(t *testing.T) { + if _, err := os.Stat("docs/architecture"); !os.IsNotExist(err) { + t.Fatal("docs/architecture should not publish stale operator architecture diagrams") + } +} + func TestGettingStartedUsesCurrentPipelineConfigShape(t *testing.T) { paths := []string{"README.md", "docs/GETTING_STARTED.md"} diff --git a/helm_chart_test.go b/helm_chart_test.go index 9447525..e34072f 100644 --- a/helm_chart_test.go +++ b/helm_chart_test.go @@ -12,7 +12,6 @@ func TestHelmChartUsesSecretSyncAPI(t *testing.T) { paths := []string{ "deploy/charts/secretsync/Chart.yaml", "deploy/charts/secretsync/values.yaml", - "docs/architecture/HLA-microservice.drawio", "docs/USAGE.md", } From ae4db3546c69e635a89cfef3d7f14ce1a5f68df8 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 16:46:48 -0500 Subject: [PATCH 33/42] docs: guard architecture audit paths --- docs/ARCHITECTURE_GAP_ANALYSIS.md | 7 +++-- docs_markdown_test.go | 49 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/docs/ARCHITECTURE_GAP_ANALYSIS.md b/docs/ARCHITECTURE_GAP_ANALYSIS.md index b3f5cae..229ecf6 100644 --- a/docs/ARCHITECTURE_GAP_ANALYSIS.md +++ b/docs/ARCHITECTURE_GAP_ANALYSIS.md @@ -15,7 +15,8 @@ SecretSync is a standalone Go module with: - Circuit breaker, request context, and observability support in `pkg`. - Docker action metadata in `action.yml`. - Optional Python binding sources under `python/secretssync`. -- Kubernetes API types under `api/v1alpha1`. +- Helm runner chart under `deploy/charts/secretsync`, rendering a CronJob and + config mount for the same CLI pipeline contract. The main runtime path is the two-phase pipeline: @@ -50,8 +51,8 @@ The main runtime path is the two-phase pipeline: tag placeholder until the first standalone repository release exists. - The Docker action should eventually move to a digest-pinned image reference once release automation can update that digest as part of publication. -- Optional Python binding and Kubernetes API surfaces need separate release - contracts if they become first-class artifacts. +- Optional Python binding sources and any future native Kubernetes runtime + surface need separate release contracts before becoming first-class artifacts. ## Development Rule diff --git a/docs_markdown_test.go b/docs_markdown_test.go index 60a3dad..63416c6 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -93,6 +93,55 @@ func TestStaleArchitectureDiagramsAreNotPublished(t *testing.T) { } } +func TestArchitectureAuditCurrentShapeReferencesExistingPaths(t *testing.T) { + content, err := os.ReadFile("docs/ARCHITECTURE_GAP_ANALYSIS.md") + if err != nil { + t.Fatalf("read docs/ARCHITECTURE_GAP_ANALYSIS.md: %v", err) + } + + text := string(content) + start := strings.Index(text, "## Current Shape") + end := strings.Index(text, "## Known Remaining Work") + if start < 0 || end < 0 || end <= start { + t.Fatal("docs/ARCHITECTURE_GAP_ANALYSIS.md should have a current shape section before known remaining work") + } + + currentShape := text[start:end] + for _, forbidden := range []string{ + "api/v1alpha1", + "Kubernetes API types", + } { + if strings.Contains(currentShape, forbidden) { + t.Fatalf("architecture audit should not document removed current path %q", forbidden) + } + } + if !strings.Contains(currentShape, "deploy/charts/secretsync") { + t.Fatal("architecture audit should document the Helm runner chart path") + } + + for _, match := range regexp.MustCompile("`([^`]+)`").FindAllStringSubmatch(currentShape, -1) { + path := match[1] + if !isArchitectureAuditRepoPath(path) { + continue + } + if _, err := os.Stat(path); err != nil { + t.Fatalf("architecture audit references missing current path %s: %v", path, err) + } + } +} + +func isArchitectureAuditRepoPath(path string) bool { + if strings.HasPrefix(path, "jbcom/") || strings.Contains(path, ":") { + return false + } + for _, prefix := range []string{"cmd/", "deploy/", "docs/", "pkg/", "python/"} { + if strings.HasPrefix(path, prefix) { + return true + } + } + return path == "pkg" || path == "action.yml" || strings.HasSuffix(path, ".go") +} + func TestGettingStartedUsesCurrentPipelineConfigShape(t *testing.T) { paths := []string{"README.md", "docs/GETTING_STARTED.md"} From abc88d51f8506dabc5e44a753339f7d0ab14539e Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 18:55:17 -0500 Subject: [PATCH 34/42] docs: align contributing guide with current architecture --- CONTRIBUTING.md | 57 +++++++++++++++++++++---------------------- docs_markdown_test.go | 29 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a09cddb..1577563 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,49 +206,47 @@ secretsync/ ├── cmd/secretsync/ # CLI application │ ├── cmd/ # Cobra commands │ └── main.go # Entry point -├── pkg/ # Public packages -│ ├── pipeline/ # Pipeline orchestration -│ ├── diff/ # Diff computation -│ └── ... -├── stores/ # Secret store implementations -│ ├── vault/ # Vault store -│ ├── aws/ # AWS Secrets Manager -│ └── ... -├── internal/ # Private packages +├── pkg/ +│ ├── client/ # Vault, AWS, and provider clients +│ ├── discovery/ # AWS Organizations and Identity Center discovery +│ ├── driver/ # Supported driver names and validation helpers +│ ├── pipeline/ # Merge, sync, graph, and execution orchestration +│ ├── diff/ # Diff computation and masking +│ └── observability/ # Metrics and request tracking +├── python/ # Optional gopy binding sources ├── docs/ # Documentation ├── examples/ # Example configurations └── deploy/ # Deployment manifests ``` -## Adding a New Secret Store +## Adding a New Secret Backend -To add support for a new secret store: +To add support for a new backend: -1. **Create store package** +1. **Create a client package** ```bash - mkdir -p stores/newstore + mkdir -p pkg/client/newbackend ``` -2. **Implement Store interface** +2. **Implement the current client shape** ```go - package newstore + package newbackend - import "github.com/jbcom/secrets-sync/pkg/store" + import "github.com/jbcom/secrets-sync/pkg/driver" - type Store struct { - // configuration fields + type Client struct { + Name string `yaml:"name,omitempty" json:"name,omitempty"` } - func (s *Store) Get(ctx context.Context, key string) ([]byte, error) { - // implementation + func (c *Client) Validate() error { + if c.Name == "" { + return driver.ErrPathRequired + } + return nil } - func (s *Store) Set(ctx context.Context, key string, value []byte) error { - // implementation - } - - func (s *Store) List(ctx context.Context, prefix string) ([]string, error) { - // implementation + func (c *Client) Driver() driver.DriverName { + return driver.DriverName("newbackend") } ``` @@ -261,9 +259,10 @@ To add support for a new secret store: } ``` -4. **Register store** - - Update pipeline config to include new store - - Add store initialization logic +4. **Register the backend** + - Add the driver name in `pkg/driver` + - Update pipeline config types and validation + - Add client initialization logic in the pipeline layer - Update documentation 5. **Add examples** diff --git a/docs_markdown_test.go b/docs_markdown_test.go index 63416c6..f8b55bb 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -130,6 +130,35 @@ func TestArchitectureAuditCurrentShapeReferencesExistingPaths(t *testing.T) { } } +func TestContributingGuideUsesCurrentRepositoryShape(t *testing.T) { + content, err := os.ReadFile("CONTRIBUTING.md") + if err != nil { + t.Fatalf("read CONTRIBUTING.md: %v", err) + } + + text := string(content) + for _, required := range []string{ + "pkg/client/", + "pkg/driver", + "pkg/pipeline", + "driver.DriverName", + } { + if !strings.Contains(text, required) { + t.Fatalf("CONTRIBUTING.md should document current repository shape %q", required) + } + } + + for _, forbidden := range []string{ + "stores/newstore", + "github.com/jbcom/secrets-sync/pkg/store", + "├── stores/", + } { + if strings.Contains(text, forbidden) { + t.Fatalf("CONTRIBUTING.md should not document removed store surface %q", forbidden) + } + } +} + func isArchitectureAuditRepoPath(path string) bool { if strings.HasPrefix(path, "jbcom/") || strings.Contains(path, ":") { return false From 360638c7e1edf98339b3dd30145f5a5b4885bd06 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 18:58:14 -0500 Subject: [PATCH 35/42] docs: fix github directory links --- docs/FAQ.md | 4 ++-- docs/GITHUB_ACTIONS.md | 2 +- docs_markdown_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 5ba17da..40754e0 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -487,9 +487,9 @@ go test -race ./... ### Where can I get help? -- **Documentation**: [docs/](https://github.com/jbcom/secrets-sync/docs) +- **Documentation**: [docs/](https://github.com/jbcom/secrets-sync/tree/main/docs) - **GitHub Issues**: For bugs, questions, and feature requests -- **Examples**: [examples/](https://github.com/jbcom/secrets-sync/examples) +- **Examples**: [examples/](https://github.com/jbcom/secrets-sync/tree/main/examples) ### How do I request a feature? diff --git a/docs/GITHUB_ACTIONS.md b/docs/GITHUB_ACTIONS.md index 4a2b82f..e750c4c 100644 --- a/docs/GITHUB_ACTIONS.md +++ b/docs/GITHUB_ACTIONS.md @@ -666,7 +666,7 @@ runs: ## Support -- **Documentation**: [Full docs](https://github.com/jbcom/secrets-sync/docs) +- **Documentation**: [Full docs](https://github.com/jbcom/secrets-sync/tree/main/docs) - **Issues**: [GitHub Issues](https://github.com/jbcom/secrets-sync/issues) ## License diff --git a/docs_markdown_test.go b/docs_markdown_test.go index f8b55bb..10f6c01 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -159,6 +159,37 @@ func TestContributingGuideUsesCurrentRepositoryShape(t *testing.T) { } } +func TestPublicGitHubDirectoryLinksUseTreeURLs(t *testing.T) { + brokenDirectoryLink := regexp.MustCompile(`https://github\.com/jbcom/secrets-sync/(docs|examples)(?:[)\s]|$)`) + var offenders []string + + for _, root := range []string{"README.md", "docs", "CONTRIBUTING.md", "SECURITY.md"} { + err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if entry.IsDir() || filepath.Ext(path) != ".md" { + return nil + } + content, readErr := os.ReadFile(path) + if readErr != nil { + return readErr + } + if brokenDirectoryLink.Match(content) { + offenders = append(offenders, path) + } + return nil + }) + if err != nil { + t.Fatalf("walk %s: %v", root, err) + } + } + + if len(offenders) > 0 { + t.Fatalf("GitHub directory links should use /tree/main/... URLs:\n%s", strings.Join(offenders, "\n")) + } +} + func isArchitectureAuditRepoPath(path string) bool { if strings.HasPrefix(path, "jbcom/") || strings.Contains(path, ":") { return false From 2889e23c1b87606b006de9cb881819681b326334 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 19:45:58 -0500 Subject: [PATCH 36/42] fix: redact pipeline json diagnostics --- cmd/secretsync/cmd/pipeline.go | 30 +++++++++++++++-- cmd/secretsync/cmd/pipeline_test.go | 52 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index 0e04a18..1285fef 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "os/signal" + "regexp" "sort" "strings" "syscall" @@ -30,6 +31,12 @@ var ( parallelism int ) +var ( + bearerTokenPattern = regexp.MustCompile(`(?i)\bBearer\s+[A-Za-z0-9._~+/=-]+`) + sensitiveAssignmentPattern = regexp.MustCompile(`(?i)\b(password|passwd|secret|secret_id|client_secret|api[_-]?key|access[_-]?key|token|authorization)(\s*[:=]\s*)(Bearer\s+\[REDACTED\]|\[[^\]]+\]|"[^"]*"|'[^']*'|[^\s,;}\]]+)`) + sensitiveURLParameterPattern = regexp.MustCompile(`(?i)([?&](?:password|passwd|secret|secret_id|client_secret|api[_-]?key|access[_-]?key|token|authorization)=)(\[[^\]]+\]|[^&#\s]+)`) +) + // pipelineCmd runs the full merge-then-sync pipeline var pipelineCmd = &cobra.Command{ Use: "pipeline", @@ -370,7 +377,7 @@ func newPipelineJSONSummary( Diff: pipelineDiff, } if runErr != nil { - summary.ErrorMessage = runErr.Error() + summary.ErrorMessage = redactPipelineDiagnostic(runErr.Error()) } targetsSeen := make(map[string]struct{}) @@ -395,7 +402,7 @@ func newPipelineJSONSummary( Diff: result.Diff, } if result.Error != nil { - item.Error = result.Error.Error() + item.Error = redactPipelineDiagnostic(result.Error.Error()) } summary.Results = append(summary.Results, item) @@ -414,3 +421,22 @@ func newPipelineJSONSummary( summary.TargetCount = len(targetsSeen) return summary } + +func redactPipelineDiagnostic(value string) string { + if value == "" { + return "" + } + + redacted := bearerTokenPattern.ReplaceAllString(value, "Bearer [REDACTED]") + redacted = sensitiveURLParameterPattern.ReplaceAllString(redacted, "${1}[REDACTED]") + return sensitiveAssignmentPattern.ReplaceAllStringFunc(redacted, func(match string) string { + if strings.Contains(match, "[REDACTED]") { + return match + } + parts := sensitiveAssignmentPattern.FindStringSubmatch(match) + if len(parts) != 4 { + return "[REDACTED]" + } + return parts[1] + parts[2] + "[REDACTED]" + }) +} diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go index cb75155..89e9097 100644 --- a/cmd/secretsync/cmd/pipeline_test.go +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -134,6 +134,58 @@ func TestNewPipelineJSONSummaryReportsFailures(t *testing.T) { } } +func TestNewPipelineJSONSummaryRedactsDiagnosticSecrets(t *testing.T) { + results := []pipeline.Result{ + { + Target: "prod", + Phase: "sync", + Success: false, + Error: errors.New( + "write failed api_key=key_123 Authorization: Bearer raw_token callback=https://example.test/hook?token=tok_456", + ), + }, + } + + summary := newPipelineJSONSummary( + results, + errors.New("pipeline failed password=hunter2 client_secret=secret_123"), + time.Second, + "", + nil, + ) + + if summary.Success { + t.Fatal("Success = true, want false") + } + for _, raw := range []string{"hunter2", "secret_123", "key_123", "raw_token", "tok_456"} { + if strings.Contains(summary.ErrorMessage, raw) { + t.Fatalf("ErrorMessage leaked %q: %s", raw, summary.ErrorMessage) + } + if strings.Contains(summary.Results[0].Error, raw) { + t.Fatalf("Results[0].Error leaked %q: %s", raw, summary.Results[0].Error) + } + } + if !strings.Contains(summary.ErrorMessage, "[REDACTED]") { + t.Fatalf("ErrorMessage missing redaction marker: %s", summary.ErrorMessage) + } + if !strings.Contains(summary.Results[0].Error, "[REDACTED]") { + t.Fatalf("Results[0].Error missing redaction marker: %s", summary.Results[0].Error) + } + if strings.Contains(summary.Results[0].Error, "[REDACTED] [REDACTED]") || strings.Contains(summary.Results[0].Error, "[REDACTED]]") { + t.Fatalf("Results[0].Error should not double-redact already redacted segments: %s", summary.Results[0].Error) + } + + encoded, err := json.Marshal(summary) + if err != nil { + t.Fatalf("json.Marshal(summary) failed: %v", err) + } + for _, raw := range []string{"hunter2", "secret_123", "key_123", "raw_token", "tok_456"} { + if strings.Contains(string(encoded), raw) { + t.Fatalf("encoded summary leaked %q: %s", raw, encoded) + } + } +} + func TestPipelineHadErrors(t *testing.T) { tests := map[string]struct { err error From 98c9f25cf727eabb1c43d0b5f1279066ea338c5f Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 19:49:02 -0500 Subject: [PATCH 37/42] docs: document pipeline json redaction --- docs/ARCHITECTURE.md | 9 ++++++--- docs/OBSERVABILITY.md | 6 ++++++ docs/SECURITY.md | 8 ++++++++ docs_security_test.go | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index dcee828..f465062 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -90,6 +90,9 @@ secretsync pipeline --config pipeline.yaml --output json ``` The JSON result envelope contains pipeline success, target count, secret change -counts, duration, per-target results, and optional diff output. Consumers should -treat diff and error fields as potentially sensitive and redact or suppress -them before writing logs, CI comments, or chat responses. +counts, duration, per-target results, and optional diff output. SecretSync +redacts common bearer tokens, password or token assignments, API key +assignments, client secrets, and matching URL query parameters from top-level +and per-target error strings before serializing this envelope. Consumers should +still treat diff and error fields as operationally sensitive and apply their own +policy before writing logs, CI comments, or chat responses. diff --git a/docs/OBSERVABILITY.md b/docs/OBSERVABILITY.md index d560cba..fd607f7 100644 --- a/docs/OBSERVABILITY.md +++ b/docs/OBSERVABILITY.md @@ -82,6 +82,12 @@ only to secured sinks with appropriate retention. If a provider returns credentials in an error string, treat that upstream behavior as a provider or configuration issue and rotate the exposed credential. +Machine-readable `secretsync pipeline --output json` result envelopes redact +common secret-bearing fragments from top-level and per-target error strings +before serialization. Treat `error_message`, per-target `error`, and +`diff_output` as operationally sensitive when forwarding them to logs, +dashboards, CI comments, or chat systems. + ## Available Metrics ### Vault Metrics diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 6dd2d9c..ef3b70d 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -23,6 +23,14 @@ operationally sensitive, but they should not contain the bytes being synced. Keep `--log-level debug` and `--log-level trace` restricted to trusted operators and secured log sinks. +Machine-readable `secretsync pipeline --output json` result envelopes redact +common secret-bearing diagnostic fragments in top-level and per-target error +strings before serialization, including bearer tokens, password or token +assignments, API key assignments, client secrets, and matching URL query +parameters. Downstream consumers should still treat `error_message`, per-target +`error`, and `diff_output` as operationally sensitive and avoid copying them to +untrusted logs, comments, or chat systems without their own policy checks. + ### Segregation of Duties SecretSync runs as an explicit pipeline command. Split duties by separating diff --git a/docs_security_test.go b/docs_security_test.go index 4580db1..8550977 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -12,6 +12,7 @@ func TestSecurityDocsDocumentLoggingContract(t *testing.T) { "raw Vault secret", "raw AWS secret", "raw client structures", + "machine-readable `secretsync pipeline --output json` result envelopes redact", } for _, path := range []string{"docs/SECURITY.md", "docs/OBSERVABILITY.md"} { From abcd6232ac9c50b9d77250b74155ff5f1d35a7f3 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 20:18:06 -0500 Subject: [PATCH 38/42] fix: write action outputs with GITHUB_OUTPUT --- action.yml | 13 ++++++++ action_docs_test.go | 45 ++++++++++++++++++++++---- cmd/secretsync/cmd/pipeline.go | 38 ++++++++++++++++++++++ cmd/secretsync/cmd/pipeline_test.go | 50 +++++++++++++++++++++++++++++ docs/ACTION_QUICK_REFERENCE.md | 12 ++++++- docs/GITHUB_ACTIONS.md | 25 +++++++++++++++ pkg/diff/diff.go | 8 ----- pkg/diff/diff_test.go | 11 +++---- 8 files changed, 179 insertions(+), 23 deletions(-) diff --git a/action.yml b/action.yml index 277fcf0..f994cca 100644 --- a/action.yml +++ b/action.yml @@ -63,6 +63,19 @@ inputs: description: "Log format: text or json" required: false default: "text" +outputs: + changes: + description: "Total changed secrets when diff output is computed" + added: + description: "Secrets that would be added or were added" + removed: + description: "Secrets that would be removed or were removed" + modified: + description: "Secrets that would be modified or were modified" + unchanged: + description: "Secrets with no detected changes" + zero_sum: + description: "true when the computed diff has no changes" runs: using: "docker" # Prefer a digest-pinned image once the release workflow can refresh the diff --git a/action_docs_test.go b/action_docs_test.go index e751a23..67bf0b6 100644 --- a/action_docs_test.go +++ b/action_docs_test.go @@ -9,13 +9,18 @@ import ( ) type actionMetadata struct { - Inputs map[string]actionInput `yaml:"inputs"` + Inputs map[string]actionInput `yaml:"inputs"` + Outputs map[string]actionOutput `yaml:"outputs"` } type actionInput struct { Default string `yaml:"default"` } +type actionOutput struct { + Description string `yaml:"description"` +} + func TestActionInputDocsMatchMetadata(t *testing.T) { actionInputs := readActionInputDefaults(t) @@ -33,9 +38,40 @@ func TestActionInputDocsMatchMetadata(t *testing.T) { } } +func TestActionOutputDocsMatchMetadata(t *testing.T) { + metadata := readActionMetadata(t) + if len(metadata.Outputs) == 0 { + t.Fatal("action.yml should declare outputs") + } + + for _, path := range []string{"docs/GITHUB_ACTIONS.md", "docs/ACTION_QUICK_REFERENCE.md"} { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + text := string(content) + for name := range metadata.Outputs { + if !strings.Contains(text, "`"+name+"`") { + t.Fatalf("%s should document action output %q", path, name) + } + } + } +} + func readActionInputDefaults(t *testing.T) map[string]string { t.Helper() + metadata := readActionMetadata(t) + inputs := make(map[string]string, len(metadata.Inputs)) + for name, input := range metadata.Inputs { + inputs[name] = input.Default + } + return inputs +} + +func readActionMetadata(t *testing.T) actionMetadata { + t.Helper() + content, err := os.ReadFile("action.yml") if err != nil { t.Fatalf("read action.yml: %v", err) @@ -45,12 +81,7 @@ func readActionInputDefaults(t *testing.T) map[string]string { if err := yaml.Unmarshal(content, &metadata); err != nil { t.Fatalf("parse action.yml: %v", err) } - - inputs := make(map[string]string, len(metadata.Inputs)) - for name, input := range metadata.Inputs { - inputs[name] = input.Default - } - return inputs + return metadata } func readDocumentedInputDefaults(t *testing.T, path string, heading string) map[string]string { diff --git a/cmd/secretsync/cmd/pipeline.go b/cmd/secretsync/cmd/pipeline.go index 1285fef..c00a2fb 100644 --- a/cmd/secretsync/cmd/pipeline.go +++ b/cmd/secretsync/cmd/pipeline.go @@ -185,6 +185,11 @@ func runPipeline(cmd *cobra.Command, args []string) error { if pipelineDiff != nil { diffOutput = p.FormatDiff(format) } + if format == diff.OutputFormatGitHub { + if outputErr := writeGitHubDiffOutputs(os.Getenv("GITHUB_OUTPUT"), pipelineDiff); outputErr != nil { + return outputErr + } + } if format == diff.OutputFormatJSON { if jsonErr := printPipelineJSONSummary(results, err, duration, diffOutput, pipelineDiff); jsonErr != nil { return jsonErr @@ -246,6 +251,39 @@ func pipelineExitCode(hasErrors bool, diffExitCode int) int { return diffExitCode } +func writeGitHubDiffOutputs(outputPath string, pipelineDiff *diff.PipelineDiff) error { + if outputPath == "" || pipelineDiff == nil { + return nil + } + + outputFile, err := os.OpenFile(outputPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) + if err != nil { + return fmt.Errorf("failed to open GitHub output file: %w", err) + } + defer outputFile.Close() + + changed := pipelineDiff.Summary.Added + pipelineDiff.Summary.Removed + pipelineDiff.Summary.Modified + outputs := []struct { + name string + value string + }{ + {name: "changes", value: fmt.Sprint(changed)}, + {name: "added", value: fmt.Sprint(pipelineDiff.Summary.Added)}, + {name: "removed", value: fmt.Sprint(pipelineDiff.Summary.Removed)}, + {name: "modified", value: fmt.Sprint(pipelineDiff.Summary.Modified)}, + {name: "unchanged", value: fmt.Sprint(pipelineDiff.Summary.Unchanged)}, + {name: "zero_sum", value: fmt.Sprintf("%t", pipelineDiff.IsZeroSum())}, + } + + for _, output := range outputs { + if _, err := fmt.Fprintf(outputFile, "%s=%s\n", output.name, output.value); err != nil { + return fmt.Errorf("failed to write GitHub output %q: %w", output.name, err) + } + } + + return nil +} + // parseOutputFormat converts string to OutputFormat func parseOutputFormat(s string) diff.OutputFormat { switch strings.ToLower(s) { diff --git a/cmd/secretsync/cmd/pipeline_test.go b/cmd/secretsync/cmd/pipeline_test.go index 89e9097..6e106c0 100644 --- a/cmd/secretsync/cmd/pipeline_test.go +++ b/cmd/secretsync/cmd/pipeline_test.go @@ -3,6 +3,8 @@ package cmd import ( "encoding/json" "errors" + "os" + "path/filepath" "strings" "testing" "time" @@ -255,3 +257,51 @@ func TestPipelineExitCode(t *testing.T) { }) } } + +func TestWriteGitHubDiffOutputs(t *testing.T) { + pipelineDiff := &diff.PipelineDiff{ + Summary: diff.ChangeSummary{ + Added: 2, + Removed: 1, + Modified: 3, + Unchanged: 5, + Total: 11, + }, + } + outputPath := filepath.Join(t.TempDir(), "github_output") + + if err := writeGitHubDiffOutputs(outputPath, pipelineDiff); err != nil { + t.Fatalf("writeGitHubDiffOutputs() failed: %v", err) + } + + content, err := os.ReadFile(outputPath) + if err != nil { + t.Fatalf("read GitHub output file: %v", err) + } + + text := string(content) + for _, expected := range []string{ + "changes=6\n", + "added=2\n", + "removed=1\n", + "modified=3\n", + "unchanged=5\n", + "zero_sum=false\n", + } { + if !strings.Contains(text, expected) { + t.Fatalf("GitHub output missing %q:\n%s", expected, text) + } + } + if strings.Contains(text, "::set-output") { + t.Fatalf("GitHub output file should not contain deprecated commands:\n%s", text) + } +} + +func TestWriteGitHubDiffOutputsNoopsWithoutOutputFile(t *testing.T) { + if err := writeGitHubDiffOutputs("", &diff.PipelineDiff{}); err != nil { + t.Fatalf("writeGitHubDiffOutputs() with empty path failed: %v", err) + } + if err := writeGitHubDiffOutputs(filepath.Join(t.TempDir(), "github_output"), nil); err != nil { + t.Fatalf("writeGitHubDiffOutputs() with nil diff failed: %v", err) + } +} diff --git a/docs/ACTION_QUICK_REFERENCE.md b/docs/ACTION_QUICK_REFERENCE.md index 4700617..ec2bb00 100644 --- a/docs/ACTION_QUICK_REFERENCE.md +++ b/docs/ACTION_QUICK_REFERENCE.md @@ -193,7 +193,17 @@ env: ### `github` (Default for Action) -Shows GitHub Actions annotations in workflow logs. +Shows GitHub Actions annotations in workflow logs and writes these action +outputs when diff computation is enabled: + +| Output | Description | +| --- | --- | +| `changes` | Total added, removed, and modified secrets | +| `added` | Secrets that would be added or were added | +| `removed` | Secrets that would be removed or were removed | +| `modified` | Secrets that would be modified or were modified | +| `unchanged` | Secrets with no detected changes | +| `zero_sum` | `true` when no changes are detected | ### `json` diff --git a/docs/GITHUB_ACTIONS.md b/docs/GITHUB_ACTIONS.md index e750c4c..daebf9a 100644 --- a/docs/GITHUB_ACTIONS.md +++ b/docs/GITHUB_ACTIONS.md @@ -555,6 +555,31 @@ Ensure `output-format` is set to `github`: output-format: 'github' # Enables GitHub Actions annotations ``` +When diff computation is enabled, the action also writes modern +`$GITHUB_OUTPUT` values: + +| Output | Description | +| --- | --- | +| `changes` | Total added, removed, and modified secrets | +| `added` | Secrets that would be added or were added | +| `removed` | Secrets that would be removed or were removed | +| `modified` | Secrets that would be modified or were modified | +| `unchanged` | Secrets with no detected changes | +| `zero_sum` | `true` when no changes are detected | + +```yaml +- name: Check for Changes + id: check + uses: jbcom/secrets-sync@secrets-sync-vX.Y.Z + with: + dry-run: 'true' + compute-diff: 'true' + output-format: 'github' + +- name: Report Summary + run: echo "Changed secrets: ${{ steps.check.outputs.changes }}" +``` + ## Exit Codes When `exit-code: 'true'` is enabled: diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index e59bf9d..7ba83ea 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -387,14 +387,6 @@ func formatHuman(diff *PipelineDiff) string { func formatGitHub(diff *PipelineDiff) string { var sb strings.Builder - // Summary as workflow output - sb.WriteString(fmt.Sprintf("::set-output name=changes::%d\n", diff.Summary.Added+diff.Summary.Removed+diff.Summary.Modified)) - sb.WriteString(fmt.Sprintf("::set-output name=added::%d\n", diff.Summary.Added)) - sb.WriteString(fmt.Sprintf("::set-output name=removed::%d\n", diff.Summary.Removed)) - sb.WriteString(fmt.Sprintf("::set-output name=modified::%d\n", diff.Summary.Modified)) - sb.WriteString(fmt.Sprintf("::set-output name=unchanged::%d\n", diff.Summary.Unchanged)) - sb.WriteString(fmt.Sprintf("::set-output name=zero_sum::%t\n", diff.IsZeroSum())) - if diff.IsZeroSum() { sb.WriteString("::notice::✅ Zero-sum: No changes detected\n") } else { diff --git a/pkg/diff/diff_test.go b/pkg/diff/diff_test.go index 80739f3..a8ce381 100644 --- a/pkg/diff/diff_test.go +++ b/pkg/diff/diff_test.go @@ -254,11 +254,8 @@ func TestFormatDiff_GitHub(t *testing.T) { output := FormatDiff(diff, OutputFormatGitHub) - if !strings.Contains(output, "::set-output name=changes::3") { - t.Error("expected changes output") - } - if !strings.Contains(output, "::set-output name=zero_sum::false") { - t.Error("expected zero_sum output") + if strings.Contains(output, "::set-output") { + t.Error("GitHub format should not use deprecated set-output commands") } if !strings.Contains(output, "::warning::") { t.Error("expected warning annotation") @@ -272,8 +269,8 @@ func TestFormatDiff_GitHubZeroSum(t *testing.T) { output := FormatDiff(diff, OutputFormatGitHub) - if !strings.Contains(output, "::set-output name=zero_sum::true") { - t.Error("expected zero_sum=true output") + if strings.Contains(output, "::set-output") { + t.Error("GitHub format should not use deprecated set-output commands") } if !strings.Contains(output, "::notice::") { t.Error("expected notice annotation for zero-sum") From d660e2598a6145555ff31932497037e10445debf Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 20:28:36 -0500 Subject: [PATCH 39/42] fix: escape github annotation data --- docs/OBSERVABILITY.md | 2 ++ docs/SECURITY.md | 2 ++ docs_security_test.go | 1 + pkg/diff/diff.go | 18 ++++++++++++++---- pkg/diff/diff_test.go | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/docs/OBSERVABILITY.md b/docs/OBSERVABILITY.md index fd607f7..0514f3a 100644 --- a/docs/OBSERVABILITY.md +++ b/docs/OBSERVABILITY.md @@ -87,6 +87,8 @@ common secret-bearing fragments from top-level and per-target error strings before serialization. Treat `error_message`, per-target `error`, and `diff_output` as operationally sensitive when forwarding them to logs, dashboards, CI comments, or chat systems. +GitHub Actions annotation output escapes workflow-command data in target names +and secret paths before writing groups, notices, or warnings. ## Available Metrics diff --git a/docs/SECURITY.md b/docs/SECURITY.md index ef3b70d..11b74ae 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -30,6 +30,8 @@ assignments, API key assignments, client secrets, and matching URL query parameters. Downstream consumers should still treat `error_message`, per-target `error`, and `diff_output` as operationally sensitive and avoid copying them to untrusted logs, comments, or chat systems without their own policy checks. +GitHub Actions annotation output escapes workflow-command data in target names +and secret paths before writing groups, notices, or warnings. ### Segregation of Duties diff --git a/docs_security_test.go b/docs_security_test.go index 8550977..476c861 100644 --- a/docs_security_test.go +++ b/docs_security_test.go @@ -13,6 +13,7 @@ func TestSecurityDocsDocumentLoggingContract(t *testing.T) { "raw AWS secret", "raw client structures", "machine-readable `secretsync pipeline --output json` result envelopes redact", + "GitHub Actions annotation output escapes workflow-command data", } for _, path := range []string{"docs/SECURITY.md", "docs/OBSERVABILITY.md"} { diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index 7ba83ea..1137b9a 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -401,17 +401,18 @@ func formatGitHub(diff *PipelineDiff) string { continue } - sb.WriteString(fmt.Sprintf("::group::Target: %s (%d changes)\n", td.Target, + sb.WriteString(fmt.Sprintf("::group::Target: %s (%d changes)\n", escapeGitHubCommandData(td.Target), td.Summary.Added+td.Summary.Removed+td.Summary.Modified)) for _, c := range td.Changes { + safePath := escapeGitHubCommandData(c.Path) switch c.ChangeType { case ChangeTypeAdded: - sb.WriteString(fmt.Sprintf("::notice::+ %s (new secret)\n", c.Path)) + sb.WriteString(fmt.Sprintf("::notice::+ %s (new secret)\n", safePath)) case ChangeTypeRemoved: - sb.WriteString(fmt.Sprintf("::warning::- %s (removed)\n", c.Path)) + sb.WriteString(fmt.Sprintf("::warning::- %s (removed)\n", safePath)) case ChangeTypeModified: - sb.WriteString(fmt.Sprintf("::notice::~ %s (modified)\n", c.Path)) + sb.WriteString(fmt.Sprintf("::notice::~ %s (modified)\n", safePath)) } } @@ -421,6 +422,15 @@ func formatGitHub(diff *PipelineDiff) string { return sb.String() } +func escapeGitHubCommandData(value string) string { + replacer := strings.NewReplacer( + "%", "%25", + "\r", "%0D", + "\n", "%0A", + ) + return replacer.Replace(value) +} + func formatCompact(diff *PipelineDiff) string { if diff.IsZeroSum() { return fmt.Sprintf("ZERO-SUM: %d secrets unchanged", diff.Summary.Unchanged) diff --git a/pkg/diff/diff_test.go b/pkg/diff/diff_test.go index a8ce381..1dbd952 100644 --- a/pkg/diff/diff_test.go +++ b/pkg/diff/diff_test.go @@ -262,6 +262,38 @@ func TestFormatDiff_GitHub(t *testing.T) { } } +func TestFormatDiff_GitHubEscapesCommandData(t *testing.T) { + diff := &PipelineDiff{ + Targets: []TargetDiff{ + { + Target: "prod%\n::warning::injected", + Changes: []SecretChange{ + { + Path: "app/secret%\r\n::error::leak", + ChangeType: ChangeTypeModified, + }, + }, + Summary: ChangeSummary{Modified: 1, Total: 1}, + }, + }, + Summary: ChangeSummary{Modified: 1, Total: 1}, + } + + output := FormatDiff(diff, OutputFormatGitHub) + + if strings.Contains(output, "prod%\n") || strings.Contains(output, "app/secret%\r\n") { + t.Fatalf("GitHub command data was not escaped:\n%s", output) + } + if strings.Contains(output, "\n::warning::injected") || strings.Contains(output, "\n::error::leak") { + t.Fatalf("GitHub command data allowed injected workflow command:\n%s", output) + } + for _, expected := range []string{"prod%25%0A::warning::injected", "app/secret%25%0D%0A::error::leak"} { + if !strings.Contains(output, expected) { + t.Fatalf("GitHub output missing escaped value %q:\n%s", expected, output) + } + } +} + func TestFormatDiff_GitHubZeroSum(t *testing.T) { diff := &PipelineDiff{ Summary: ChangeSummary{Unchanged: 5, Total: 5}, From c18bde8fa4ca32ed542dc08d6b6c9de80ad037cb Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 22:22:29 -0500 Subject: [PATCH 40/42] docs: rename architecture audit --- ...CTURE_GAP_ANALYSIS.md => ARCHITECTURE_AUDIT.md} | 6 +++--- docs_markdown_test.go | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) rename docs/{ARCHITECTURE_GAP_ANALYSIS.md => ARCHITECTURE_AUDIT.md} (94%) diff --git a/docs/ARCHITECTURE_GAP_ANALYSIS.md b/docs/ARCHITECTURE_AUDIT.md similarity index 94% rename from docs/ARCHITECTURE_GAP_ANALYSIS.md rename to docs/ARCHITECTURE_AUDIT.md index 229ecf6..c966c5d 100644 --- a/docs/ARCHITECTURE_GAP_ANALYSIS.md +++ b/docs/ARCHITECTURE_AUDIT.md @@ -1,8 +1,8 @@ # Architecture Audit This file records the current architecture status of the standalone -`jbcom/secrets-sync` repository. It replaces the earlier migration-era gap -analysis that referenced old monorepo paths such as `stores/vault/vault.go`. +`jbcom/secrets-sync` repository. It replaces earlier migration-era notes that +referenced old monorepo paths such as `stores/vault/vault.go`. ## Current Shape @@ -45,7 +45,7 @@ The main runtime path is the two-phase pipeline: - The Docker action image tag remains `jbcom/secretssync:v1` until digest refresh can be automated. -## Known Remaining Work +## Future Release Work - The Marketplace and action docs should continue to use the component release tag placeholder until the first standalone repository release exists. diff --git a/docs_markdown_test.go b/docs_markdown_test.go index 10f6c01..b4ed022 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -94,16 +94,16 @@ func TestStaleArchitectureDiagramsAreNotPublished(t *testing.T) { } func TestArchitectureAuditCurrentShapeReferencesExistingPaths(t *testing.T) { - content, err := os.ReadFile("docs/ARCHITECTURE_GAP_ANALYSIS.md") + content, err := os.ReadFile("docs/ARCHITECTURE_AUDIT.md") if err != nil { - t.Fatalf("read docs/ARCHITECTURE_GAP_ANALYSIS.md: %v", err) + t.Fatalf("read docs/ARCHITECTURE_AUDIT.md: %v", err) } text := string(content) start := strings.Index(text, "## Current Shape") - end := strings.Index(text, "## Known Remaining Work") + end := strings.Index(text, "## Future Release Work") if start < 0 || end < 0 || end <= start { - t.Fatal("docs/ARCHITECTURE_GAP_ANALYSIS.md should have a current shape section before known remaining work") + t.Fatal("docs/ARCHITECTURE_AUDIT.md should have a current shape section before future release work") } currentShape := text[start:end] @@ -130,6 +130,12 @@ func TestArchitectureAuditCurrentShapeReferencesExistingPaths(t *testing.T) { } } +func TestArchitectureAuditDoesNotKeepMigrationGapFilename(t *testing.T) { + if _, err := os.Stat("docs/ARCHITECTURE_GAP_ANALYSIS.md"); !os.IsNotExist(err) { + t.Fatal("docs/ARCHITECTURE_GAP_ANALYSIS.md should not be published in the standalone repository") + } +} + func TestContributingGuideUsesCurrentRepositoryShape(t *testing.T) { content, err := os.ReadFile("CONTRIBUTING.md") if err != nil { From f07f4ebc4b6970f69177616852bed3c12f2005c2 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 22:25:23 -0500 Subject: [PATCH 41/42] docs: link architecture audit --- README.md | 1 + docs/ARCHITECTURE.md | 3 +++ docs_markdown_test.go | 12 ++++++++++++ 3 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 324ecdd..48bff9a 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,7 @@ See [GitHub Actions documentation](./docs/GITHUB_ACTIONS.md) for complete usage ### Core Documentation - [🏗️ Architecture Overview](./docs/ARCHITECTURE.md) - System design and components +- [🔎 Architecture Audit](./docs/ARCHITECTURE_AUDIT.md) - Current implementation and release-contract status - [🔄 Two-Phase Pipeline](./docs/TWO_PHASE_ARCHITECTURE.md) - Merge → Sync architecture - [⚙️ Pipeline Configuration](./docs/PIPELINE.md) - Configuration reference - [🚀 Deployment Guide](./docs/DEPLOYMENT.md) - Production deployment patterns diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f465062..145a8a9 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -5,6 +5,9 @@ executing a configured merge, sync, or full pipeline operation. Kubernetes and GitHub Actions deployments wrap that same CLI contract instead of introducing a separate controller API. +See [Architecture Audit](./ARCHITECTURE_AUDIT.md) for the current +implementation-status checklist and release-contract notes. + ## Runtime Shape ```text diff --git a/docs_markdown_test.go b/docs_markdown_test.go index b4ed022..b1c0e60 100644 --- a/docs_markdown_test.go +++ b/docs_markdown_test.go @@ -136,6 +136,18 @@ func TestArchitectureAuditDoesNotKeepMigrationGapFilename(t *testing.T) { } } +func TestArchitectureAuditIsDiscoverableFromPublicDocs(t *testing.T) { + for _, path := range []string{"README.md", "docs/ARCHITECTURE.md"} { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + if !strings.Contains(string(content), "ARCHITECTURE_AUDIT.md") { + t.Fatalf("%s should link to docs/ARCHITECTURE_AUDIT.md", path) + } + } +} + func TestContributingGuideUsesCurrentRepositoryShape(t *testing.T) { content, err := os.ReadFile("CONTRIBUTING.md") if err != nil { From f0ccc6f788f4eb32a0d20deb5e6196247f457956 Mon Sep 17 00:00:00 2001 From: Jon Bogaty Date: Wed, 10 Jun 2026 22:54:56 -0500 Subject: [PATCH 42/42] test: pin documented third-party actions --- docs/DEPLOYMENT.md | 4 +- workflow_pinning_test.go | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 791be88..341e5d2 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -117,8 +117,8 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v6 - - uses: aws-actions/configure-aws-credentials@v5 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6.2.0 with: role-to-assume: arn:aws:iam::123456789012:role/SecretSyncRunner aws-region: us-east-1 diff --git a/workflow_pinning_test.go b/workflow_pinning_test.go index 7db0434..82bece8 100644 --- a/workflow_pinning_test.go +++ b/workflow_pinning_test.go @@ -54,6 +54,47 @@ func TestPublishingChecklistMatchesWorkflowActionPins(t *testing.T) { } } +func TestMaintainedDocsPinThirdPartyActions(t *testing.T) { + paths := markdownAndExampleWorkflowFiles(t) + var offenders []string + + for _, path := range paths { + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + for index, line := range strings.Split(string(content), "\n") { + matches := actionRefPattern.FindStringSubmatch(line) + if matches == nil { + continue + } + + uses := strings.TrimSpace(matches[1]) + if shouldSkipDocumentedActionPin(uses) { + continue + } + + _, ref, found := strings.Cut(uses, "@") + version := "" + if len(matches) > 2 { + version = matches[2] + } + if !found || !pinnedSHAPattern.MatchString(ref) { + offenders = append(offenders, path+":"+itoa(index+1)+": "+uses) + continue + } + if !actionVersionCommentPattern.MatchString(version) { + offenders = append(offenders, path+":"+itoa(index+1)+": missing stable version comment for "+uses) + } + } + } + + if len(offenders) > 0 { + t.Fatalf("maintained docs/examples must pin third-party actions to exact commit SHAs:\n%s", strings.Join(offenders, "\n")) + } +} + func workflowActionPins(t *testing.T) map[string]workflowActionPin { t.Helper() @@ -120,6 +161,50 @@ func workflowActionPins(t *testing.T) map[string]workflowActionPin { return pins } +func markdownAndExampleWorkflowFiles(t *testing.T) []string { + t.Helper() + + roots := []string{"README.md", "docs", "examples"} + var paths []string + for _, root := range roots { + info, err := os.Stat(root) + if err != nil { + t.Fatalf("stat %s: %v", root, err) + } + if !info.IsDir() { + paths = append(paths, root) + continue + } + err = filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { + if err != nil { + return err + } + if entry.IsDir() { + return nil + } + switch filepath.Ext(path) { + case ".md", ".yml", ".yaml": + paths = append(paths, path) + } + return nil + }) + if err != nil { + t.Fatalf("walk %s: %v", root, err) + } + } + return paths +} + +func shouldSkipDocumentedActionPin(uses string) bool { + if strings.HasPrefix(uses, "./") || strings.HasPrefix(uses, "docker://") { + return true + } + if strings.HasPrefix(uses, "jbcom/secrets-sync@") { + return true + } + return false +} + func publishingChecklistPins(t *testing.T) map[string]workflowActionPin { t.Helper()

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 Qt5DkU=n&EZ4 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