feat(co-importer): CO to ACS scan config importer#19636
feat(co-importer): CO to ACS scan config importer#19636
Conversation
Standalone Go tool (scripts/compliance-operator-importer) that reads Compliance Operator ScanSettingBinding/ScanSetting resources from a Kubernetes cluster and creates equivalent ACS v2 compliance scan configurations. Phase 1: create-only with idempotency (skip existing), dry-run mode, exponential backoff retry, JSON report output, and structured exit codes (0/1/2). Infrastructure changes to support the standalone sub-module: - go.work workspace file so go vet/staticcheck/roxvet can typecheck the importer module alongside the main rox module - .golangci.yml: exclude importer path from linter path patterns - tools/roxvet/validateimports: skip packages outside the rox module prefix instead of reporting them as errors (these appear via go.work when analyzing workspace packages from other modules) Prompt: Build a standalone CO->ACS scheduled scan importer as a complete Go sub-module under scripts/compliance-operator-importer/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ScanSettingBinding: profiles and settingsRef are top-level fields, not nested under spec (spec is always empty in the actual CR). ScanSetting: schedule is a top-level field, not nested under complianceSuiteSettings.schedule as the spec document assumed. Found during live smoke-test against the cluster. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ScanSetting.schedule is a top-level field, not nested under complianceSuiteSettings.schedule as the spec originally assumed. ScanSettingBinding.profiles is also top-level, not under spec. Discovered during live smoke-test against the cluster. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ns (Slice H) Rename flags/env vars to match roxctl patterns: --endpoint/ROX_ENDPOINT, ROX_API_TOKEN, ROX_ADMIN_PASSWORD, ROX_ADMIN_USER. Remove explicit --acs-auth-mode in favor of auto-inference from which env var is set. Unify --acs-cluster-id and --source-kubecontext into a single --cluster flag that accepts UUID, name, or ctx= overrides. Add --overwrite-existing for update-in-place (IMP-IDEM-008/009). Add --username with default "admin". Specs updated to reflect the new contract. Extensive unit tests (~60 cases) freeze the new behavior including edge cases. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
hack/check-spec-coverage.sh extracts all IMP-* requirement IDs from specs/ and verifies each has at least one matching test in *_test.go. Handles range notation (IMP-CLI-001..016) and normalizes underscored Go test names to hyphenated form for matching. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add e2e/e2e_test.go (build tag: e2e) and hack/run-e2e.sh wrapper. Tests run against a real ACS + Compliance Operator cluster using ROX_ENDPOINT and ROX_API_TOKEN/ROX_ADMIN_PASSWORD env vars. Covers IMP-ACC-001 (CO resources listable), ACC-002 (auth preflight), ACC-003 (dry-run no writes), ACC-004 (apply creates configs), ACC-005 (idempotent second run), ACC-007 (invalid token fails fast), ACC-012 (problems have fix hints), ACC-014 (overwrite updates), ACC-017 (auto-discover cluster ID). Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lice I) Drop --kubeconfig, --kubecontext, and --cluster flags. The importer now uses all contexts from the merged kubeconfig by default, with --context (repeatable) as an opt-in filter. ACS cluster ID is always auto-discovered via admission-control ConfigMap, OpenShift ClusterVersion, or Helm secret. Specs cleaned: removed tombstone entries for deleted requirement IDs, removed Old/New change tables, removed all temporal language referencing past behavior that was never released. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… (IMP-CLI-016a) When preflight fails due to a TLS certificate verification error (e.g. self-signed cert), the error message now suggests --ca-cert-file or --insecure-skip-verify instead of the generic "check network connectivity" hint, which was misleading. Adds spec requirement IMP-CLI-016a and a test that verifies the hint content for untrusted certificates. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…o backlog Update traceability matrix with IMP-IMG-001..006 from the container image spec. Add Slice J definition to the implementation backlog. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rence Replace the spec-process-only README with a practical user guide covering quick start, authentication, multi-cluster usage, flags reference, mapping rules, exit codes, JSON report shape, and demo instructions. Also ignore the built binary in .gitignore. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When all three discovery methods fail (admission-control ConfigMap, OpenShift ClusterVersion, helm-effective-cluster-name Secret), the error now lists each method's failure reason instead of a generic "all methods failed" message. This makes it immediately clear whether the issue is auth (e.g. expired kubeconfig credentials), missing resources, or something else. Before: all discovery methods failed to resolve ACS cluster ID After: all discovery methods failed to resolve ACS cluster ID: - admission-control ConfigMap: ... Unauthorized - OpenShift ClusterVersion: ... Unauthorized - helm-effective-cluster-name Secret: ... Unauthorized Adds spec scenario IMP-MAP-016a for the detailed error contract. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ntial collisions When KUBECONFIG lists multiple files (e.g. config:config-secured-cluster), kubectl merges them into a single view. If both files define a user named "admin" with different certificates, the merge silently picks one and the other cluster gets wrong credentials — causing confusing auth failures. The importer now loads each kubeconfig file in isolation via ExplicitPath, so user/cluster/context entries in one file never interfere with another. Duplicate context names across files are allowed and both are processed with their own credentials. Changes: - cluster_source.go: split KUBECONFIG into individual files, load each independently via clientcmd.ExplicitPath, enumerate contexts per file - cofetch/client.go: add NewClientFromRestConfig to accept a pre-built rest.Config (avoids re-loading merged kubeconfig) - spec IMP-CLI-003: updated to specify per-file isolation semantics - cluster_source_test.go: new tests for per-file loading, credential isolation, duplicate context handling, and --context filtering Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…20a) Merge conflict problems (e.g. same-name SSBs with different profiles across clusters) were collected into the report but never printed to the console, leaving users with a cryptic "merged into 0" message and no explanation. Add r.status.Warnf() for each merge problem so the conflict reason is visible inline. Also includes RunMultiCluster orchestrator (multi_cluster.go) and updates specs: - Fix merge conflict scenarios: category "mapping" → "conflict" (matches code and models.CategoryConflict) - Add IMP-MAP-020a console output requirement - Add adopt and wire-format spec scenarios - Update traceability matrix with IMP-MAP-020a Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…side The previous demo modified the ACS scan config schedule directly via API, but after SSB adoption ACS pushes its schedule back down to the cluster ScanSetting — so there was no real conflict visible. Changed to simulate drift from the Kubernetes side: update the original ScanSetting schedule (02:00 → 05:00) and patch the SSB's settingsRef back to it. Now the importer reads 05:00 from k8s while ACS has 02:00, showing a genuine drift that --overwrite-existing resolves. Also fixed cleanup to delete ACS-created ScanSettings (named after SSBs). Tested end-to-end in non-interactive mode (DEMO_AUTO=1 DEMO_PAUSE=0). Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The drift scenario now patches the ACS-managed ScanSetting directly on the cluster (kubectl patch scansetting <ssb-name>). ACS does not detect this change, so the UI still shows the original schedule while scans actually run on the new one — a silent drift. This is more realistic than the previous version (which patched the SSB's settingsRef back to a different ScanSetting) and demonstrates the exact gap the importer fills: reading the actual cluster state and syncing ACS to match. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… (IMP-MAP-004a)
The ACS v2 Schedule proto defines daysOfWeek (repeated int32) not a
"weekly" wrapper. The previous ACSWeekly struct serialized to
{"weekly":{"day":0}} which the gRPC gateway silently ignored — weekly
scans were treated as daily.
Replace ACSWeekly with ACSDaysOfWeek{Days []int32} matching the proto.
Add wire-format tests (IMP-MAP-004a..d) that serialize payloads to JSON
and assert field names match proto/api/v2/common.proto.
Partially generated by AI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When CreateScanConfiguration or UpdateScanConfiguration returns a non-2xx status, the error message now includes a snippet of the response body. This makes it clear *why* the ACS API rejected the request (e.g. "Unable to find all profiles for scan configuration"). Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…PT-001..008) After the importer creates a scan config in ACS, ACS pushes a ScanSetting to the cluster with the same name. The SSB still references the old ScanSetting, so it's not managed by ACS yet. The adoption step: 1. Polls for the ACS-created ScanSetting to appear on the cluster 2. Patches the SSB's settingsRef.name to the new ScanSetting 3. Handles timeouts (warning, not error) and partial multi-cluster success independently per cluster New packages: - internal/adopt: adoption logic with poll/timeout/patch - internal/merge: SSB merging across clusters with conflict detection - internal/status: stage-by-stage console progress output Also adds PatchSSBSettingsRef to the COClient interface and wires adoption into both single-cluster (Run) and multi-cluster (RunMultiCluster) paths. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dockerfile: multi-stage build with ubi9-micro base, CGO_ENABLED=0 static binary, multi-arch support (amd64+arm64) - Makefile: build, test, lint, image targets - .dockerignore: exclude test fixtures and vendor from build context - Spec 07: container image requirements and acceptance criteria Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
hack/demo-seed.sh creates ScanSetting + ScanSettingBindings on the current cluster for demo/testing purposes. Tracks the last seed ID in hack/.demo-seed-id to enable cleanup on re-run. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…output Three issues fixed: 1. Non-transient HTTP errors (400, 401, etc.) only showed the status code in the Reason field but not the response body detail. Now Reason includes the full error message from the ACS API. 2. Multi-cluster fail path printed action.Reason instead of action.Err, losing the response body. Now checks action.Err first, matching the single-cluster code path. 3. Multi-cluster mapping/ScanSetting errors were collected into the problem collector but never printed to the console, causing SSBs to be silently dropped. Now emits Warnf for both ScanSetting fetch failures and mapping errors (e.g. unsupported cron step notation). Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrapper script that auto-mounts kubeconfig files and forwards ACS auth env vars so running via container is a one-liner: ROX_API_TOKEN=... ./run.sh --endpoint central.example.com --dry-run Handles KUBECONFIG with multiple colon-separated paths, forwards ROX_ENDPOINT, ROX_API_TOKEN, ROX_ADMIN_PASSWORD, ROX_ADMIN_USER. Supports IMAGE and CONTAINER_RT overrides. Also reverts Makefile IMAGE default to localhost/ (local build target). Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… cluster When the importer creates a scan config in ACS, ACS pushes a ScanSetting to the cluster. The adoption step then patches the SSB's settingsRef to point to it. But if a ScanSetting with that name already existed before reconciliation, the adoption poll would find it immediately and patch the SSB onto a resource ACS doesn't control. Fix: snapshot which ScanSettings (named after SSBs) exist on each cluster before reconciliation. During adoption, if the target name was already in the snapshot, skip with a warning instead of patching. Partially generated by AI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29242324 | Triggered | Username Password | 84b000a | scripts/compliance-operator-importer/internal/config/config_test.go | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
Skipping CI for Draft Pull Request. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #19636 +/- ##
==========================================
+ Coverage 49.32% 49.43% +0.11%
==========================================
Files 2737 2751 +14
Lines 206445 208120 +1675
==========================================
+ Hits 101823 102880 +1057
- Misses 97075 97644 +569
- Partials 7547 7596 +49
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Description
Standalone CLI tool that reads Compliance Operator ScanSettingBinding resources from Kubernetes clusters and creates equivalent scan configurations in ACS via the v2 API.
Problem: Migrating from Compliance Operator scheduled scans to ACS-managed compliance scans requires manually recreating each scan configuration. For clusters with many ScanSettingBindings across multiple clusters, this is tedious and error-prone.
Solution: A standalone Go binary (
compliance-operator-importer) underscripts/compliance-operator-importer/that:Usage
Key features
--overwrite-existingto update existing configsInfrastructure changes
go.work+go.work.sumat repo root (separate Go module).golangci.ymlexclusion for the importer pathtools/roxvetskip for non-rox packagesUser-facing documentation
Testing and quality
Automated testing
How I validated my change
go test ./...(all pass)run.shwrapper with single and multiple kubeconfigs