fix(jit): support oci:// sources in JIT auto-provisioning @zack-is-cool (#2747)
## what- JIT auto-provisioning (
before.terraform.inithook, e.g.atmos terraform plan <component> -s <stack>) now supportsoci://component sources, matching whatatmos vendor pullalready supported. - Relocated the OCI-fetch implementation (image pull, auth precedence, tar extraction) from
internal/execinto a new sharedpkg/ocipackage, so both the legacy vendor-pull path and the JIT auto-provisioner can reach it without an import cycle. pkg/provisioner/source.VendorSourcenow branches onvendor.IsOCIURI(uri)and callsoci.ProcessImageinstead of go-getter foroci://sources.- Added support for OpenTofu's native "install modules from OCI registries" format (
artifactType: application/vnd.opentofu.modulepkg, a ZIP-archive layer) — real registries publishing modules this way previously failed witharchive/tar: invalid tar headerbecause the puller assumed every layer was a tar+gzip stream. - OCI pulls are now bounded by a timeout (10 minutes, matching the existing go-getter path) instead of being able to hang indefinitely on a slow/unresponsive registry.
- Zip extraction is capped against decompression-bomb amplification (bounded archive and per-entry sizes).
- Added an in-process fake OCI registry test helper (
pkg/oci/ocitest, both tar and zip layouts) so the new tests are fully hermetic — no real network or registry dependency. - Added end-to-end regression tests reproducing the reported scenario and the OpenTofu module-package scenario.
why
- A component with
provision.workdir.enabled: trueand anoci://source fails when JIT-provisioned with go-getter's own error,download not supported for scheme 'oci', even though the identical source works fine withatmos vendor pull. - While validating the fix against a real registry, a second real-world gap surfaced: registries distributing modules in OpenTofu's native OCI format use ZIP layers, which the puller couldn't extract at all.
- Code review (CodeRabbit) flagged that the OCI pull path had no timeout, unlike its sibling go-getter path, and that zip extraction had no size bound — both addressed here.
references
Closes #2716
Summary by CodeRabbit
- New Features
- Added an exported OCI image processing entry point and enabled OCI-native downloading for component, mixin, and vendor sources (
oci://). - Added ZIP-aware OCI layer extraction and improved in-process OCI test registries (tar and ZIP layouts).
- Enabled
oci://sources for JIT auto-provisioning.
- Added an exported OCI image processing entry point and enabled OCI-native downloading for component, mixin, and vendor sources (
- Bug Fixes
- Bounded OCI processing with a 10-minute timeout, improved GHCR authentication fallback, and refined layer-extraction error reporting and recognized artifact types (Terraform/OpenTofu).
- Tests
- Added/expanded coverage for safe tar/ZIP extraction, OCI registry round-trips, ZIP media type handling, and
oci://vendor/JIT success and failure cases.
- Added/expanded coverage for safe tar/ZIP extraction, OCI registry round-trips, ZIP media type handling, and
- Documentation
- Published a blog post and updated the roadmap for
oci://JIT support.
- Published a blog post and updated the roadmap for
feat(terraform): add --all/--affected bulk execution to terraform init @osterman (#2742)
## what- Add
--all,--affected,--max-concurrency,--failure-mode, and--log-orderflags toatmos terraform init, matching the bulk-execution flags already onapply/plan/destroy. - Fix the scheduler's
supportsTerraformConcurrencygate, which silently capped--max-concurrencyto1for any subcommand it didn't explicitly recognize (includinginit). initkeeps the natural forward dependency order (prerequisites before dependents), unlikedestroy, which reverses the graph.- Add unit test coverage for the new flags and the concurrency/ordering behavior, plus a new "Graph-backed Bulk Init" docs section and a changelog post.
why
--all/--affectedlanded onapply/plan/destroywhen Terraform bulk execution moved onto the scheduler-backed dependency graph (#2466), butinitwas left out.- Reinitializing every component after a provider upgrade, or bootstrapping a new environment, required scripting a loop over components by hand.
references
- Closes #2375
Summary by CodeRabbit
-
New Features
- Added bulk execution support to
terraform initwith--alland--affected. - Added configurable concurrency, failure handling, and log ordering through
--max-concurrency,--failure-mode, and--log-order. - Initialization now follows forward dependency order, processing prerequisites before dependents.
- Added environment variable equivalents for the new options.
- Added bulk execution support to
-
Documentation
- Added usage guidance and examples for bulk Terraform initialization.
feat(claude): autonomous PR merge-readiness automation @osterman (#2718)
## WhatBuilds a full autonomous PR merge-readiness system for Claude Code sessions in this repo, layered up from an initial hourly rebase-and-CodeRabbit loop into a complete one-shot/recurring check-and-fix pipeline:
pr-maintenance-loopskill — schedules the check hourly via Claude Code's nativeCronCreate/ScheduleWakeupprimitives (not GitHub Actions, no external service). CallsCronCreatedirectly rather than the generic/loopskill, since this loop is inherently tied to the localgit/ghsession (signing key, checkout state) and has no cloud-compatible equivalent.fix-allskill — the one-shot merge-readiness passpr-maintenance-loopruns every cycle: sync withorigin/main, check CI, resolve CodeRabbit threads, patch-scoped lint, patch-scoped test/coverage, and a final readiness check that announces (via thesayskill's audible nudge, plus a written summary) once the PR needs nothing but human final review. That readiness check also reconciles the PR title/description against the patch's full accumulated scope before announcing, using a narrowly-scopedgh pr edit --title/--body-filepermission (labels/reviewers/base/milestone stay denied and human-owned).lint/test-coverageskills — patch-aware (--new-from-rev=origin/main) lint and test/coverage checks reused both standalone and fromfix-all.sayskill — a macOS audible nudge (say) for every human-attention exit path, plus the one positive "ready for final review" case.- New agents —
lint-fix,test-coverage-fix,merge-conflict-resolve, andcoderabbit-review(existing, reused) do the actual fixing/resolving work each skill delegates to. atmos fixcustom commands (.atmos.d/fix.yaml) —sync/ci/threads/comments/lint/coverage/tests/--all, the mechanical half each skill step wraps..claude/settings.json— the real enforcement boundary: a narrow allow/deny list covering exactly the git/gh/go commands this automation needs, with explicit denies for force-push,git reset --hard/clean,gh pr merge/close/edit --base/--add-reviewer/--milestone/--add-label, and edits to.github/workflows/**,Makefile,go.mod,go.sum.CLAUDE.md— points every future session/worktree at the loop.
Why
PR maintenance chores — rebasing against main, responding to CodeRabbit threads, keeping lint/coverage green, and knowing when a PR is actually ready for a human's final pass — currently need manual attention every cycle. This automates the full loop hourly in any worktree, using only the local git/gh session already in use (no new external service or secrets), while keeping merge fully human-gated, treating all PR/CodeRabbit content as untrusted data rather than instructions, and giving an explicit audible+written signal once a PR is genuinely ready for review instead of leaving that judgment call to whoever happens to check next.
References
None — internal Claude Code tooling change, no linked issue.
Summary by CodeRabbit
-
New Features
- Added commands for synchronizing branches, checking CI, reviewing threads, fixing lint issues, and measuring patch coverage.
- Added an optional hourly PR maintenance loop and one-time merge-readiness workflow.
- Added automated handling for eligible review comments and merge conflicts.
-
Documentation
- Added guidance for maintenance workflows, linting, test coverage, notifications, and available automation agents.
-
Security
- Added safeguards restricting tool actions and blocking destructive or sensitive operations.
🚀 Enhancements
fix(git): support self-hosted Git hosts in describe affected @dp89 (#2543)
What
Self-hosted Git hosts (GitHub Enterprise Server, GitLab self-managed, Bitbucket Server, etc.) currently fail atmos describe affected with:
Error: repository host '<host>' not supported
The error originates in GetRepoInfo (pkg/git/git.go) and the --upload path in internal/exec/describe_affected.go. Both call into kubescape/go-git-url, which only recognizes github.com, gitlab.com, and Azure DevOps. Any other host is rejected before atmos's local diff logic gets a chance to run — even though the parsed RepoHost / RepoOwner / RepoName metadata is only consumed by the --upload to Atmos Pro, not by the local affected-stack computation itself.
This PR adds ParseGenericGitURL, a fallback parser covering the URL shapes Git itself supports (http(s)://, ssh://, and scp-style). It's wired through a small shared helper, ParseRepoURL, used by both call sites:
- Try the canonical parser first.
- If it fails, fall back to the generic parser.
- If both fail (a genuinely malformed URL like
not-a-valid-url), surface the canonical error so existing error semantics are preserved.
Why
atmos describe affectedis the documented mechanism for matrix-fan-out CI plans, but it's unusable on self-hosted Git today — even though the feature doesn't actually need the parsed metadata.- Other users have hit the same limitation (see the SweetOps thread under References), but it isn't tracked as an upstream issue, and there's no config option, env var, or flag to bypass the parser.
- The fallback only executes when the canonical parser fails, so every existing code path is byte-for-byte unchanged for
github.com/gitlab.com/ Azure DevOps users. No new config, no new env var, no new flag, and no new dependency — the fallback uses onlynet/urlandregexpfrom the standard library.
Scope of behavior change
| URL type | Before | After |
|---|---|---|
| github.com / gitlab.com / Azure DevOps | ✅ works | ✅ works (same path) |
| gitlab.example.com (kubescape substring match) | ✅ works | ✅ works (same path) |
| GHES / GitLab self-managed / Bitbucket Server | ❌ errors | ✅ works (fallback) |
| Genuinely malformed (not-a-valid-url) | ❌ errors | ❌ errors (preserved) |
All six pre-existing TestGetRepoInfo cases continue to pass without modification.
Test plan
go test -count=1 ./pkg/git/...
go vet ./pkg/git/... ./internal/exec/...
gofmt -l pkg/git/git.go pkg/git/git_test.go internal/exec/describe_affected.go
All three pass cleanly. Four new regression tests in pkg/git/git_test.go cover the shapes the canonical parser rejects:
- GHES over SSH
- GHES over HTTPS
- Nested-path HTTPS on a non-recognized host
ssh://with an explicit port
References
- SweetOps thread reporting the same error: https://www.linen.dev/s/sweetops/t/26768542/i-am-trying-to-run-atmos-describe-affected-using-a-self-host
- Affected call sites:
pkg/git/git.go—GetRepoInfo(used byinternal/exec/describe_affected_helpers.goandinternal/exec/pro.go)internal/exec/describe_affected.go—uploadableQuery(the--uploadpath to Atmos Pro)
fix(io): migrate fmt.Fprintf/Println anti-patterns to pkg/ui, pkg/data @osterman (#2713)
## what- Migrate every remaining raw
fmt.Fprintf/fmt.Fprintln/fmt.Printlncall outsidepkg/io/pkg/uito the sanctionedui.*/data.*API across ~40 files (AI permission prompts, devcontainer/kubeconfig debug diagnostics, CI annotations/log groups, the Cobra root command,pkg/manifest,pkg/runner/stepcast recording, and more). - Delete the pure print-forwarding shims in
pkg/utils(PrintMessage,PrintfMessageToTUI,PrintfMarkdown*) and migrate all ~50 call sites directly ontodata.*/ui.*, consolidating onto the already-establishedui.Markdown/ui.MarkdownMessagerenderer instead of a second, bespoke one. - Add
data.WriteUnmasked/WriteUnmaskedf, an explicit escape hatch for the one legitimate case where masking must not apply (atmos auth env/atmos envemitting real credential values for shell eval). - Add
ui.MarkdownNoWrap/MarkdownMessageNoWrapfor deterministic, snapshot-stable single-line notices (used by the telemetry disclosure). - Fix
RootCmd's default output writer to route through the masked I/O context instead of rawos.Stdout, and extract the oversized Cobra help/usage closures into named helpers while there. - Correct
pkg/devcontainer'sShowConfig/Listoutput to the data channel (primary command output) instead of the UI channel, and update the affected CLI golden snapshots to match.
why
- CLAUDE.md bans raw
fmt.Fprintf/fmt.Printlnoutsidepkg/io/pkg/uibecause it bypasses secret masking, TTY/color degradation, and--castrecording. Several call sites found in this audit (AI permission prompts, devcontainer/kubeconfig debug output, CI annotations, the Cobra help writer) genuinely bypassed masking entirely. - The
pkg/utilsprint helpers were pure forwarding shims duplicatingpkg/ui/pkg/data, adding an unnecessary second code path for callers to reason about; deleting them and routing directly through the canonical API reducespkg/utils's surface area per this repo's ongoing effort to empty that package out. atmos auth env/atmos envneed one legitimate, explicit way to emit unmasked output (the whole point of those commands is exporting real credentials foreval), so a dedicatedWriteUnmaskedAPI makes that intent explicit instead of ad hocfmt.Printcalls.
references
Summary by CodeRabbit
-
New Features
- Added deterministic no-wrap Markdown rendering for support/telemetry-style notices.
- Improved CLI help/pager and interactive help flows for more consistent output.
- Updated consent/permission prompts to handle non-interactive terminals more safely.
-
Bug Fixes
- Improved error propagation when output writing fails across commands and formats.
- Improved handling of masked vs unmasked output for sensitive data and environment exports.
-
Style
- Standardized user-facing messaging (info/success/warning) for a more consistent CLI experience.
-
Tests
- Expanded and stabilized UI/output test coverage, including snapshot updates.