Skip to content

Update auth docs and implement GitHub providers#1683

Open
osterman wants to merge 3 commits intomainfrom
osterman/github-identity-keychain
Open

Update auth docs and implement GitHub providers#1683
osterman wants to merge 3 commits intomainfrom
osterman/github-identity-keychain

Conversation

@osterman
Copy link
Member

@osterman osterman commented Oct 20, 2025

what

This PR implements GitHub User and GitHub App authentication providers, enhancing Atmos's capabilities for secure credential management in various workflows. It also refactors the authentication documentation to improve organization and discoverability.

why

  • Enhance Security: Provide secure, short-lived tokens for GitHub interactions, reducing risks associated with long-lived Personal Access Tokens.
  • Improve Developer Experience: Seamlessly integrate GitHub authentication into local development and CI/CD pipelines.
  • Centralize Credential Management: Allow users to manage GitHub credentials via Atmos, storing tokens securely in OS keychains.
  • Modular Documentation: Create dedicated documentation pages for each GitHub provider (github/user, github/app, github/oidc) for better maintainability and discoverability.
  • Increase Test Coverage: Achieve 80.7% test coverage for the new providers using mocks for external dependencies.

references

  • GitHub User Provider: Implements OAuth Device Flow, inspired by ghtkn. User tokens are cached in OS keychains with an 8-hour lifetime.
  • GitHub App Provider: Uses JWT signing for installation tokens, offering granular permissions and 1-hour token lifetimes.
  • Git Credential Helper: Integrated via atmos auth git-credential for seamless Git operations.
  • Logout Command: Added atmos auth logout for keychain cleanup and guidance on token revocation.
  • Documentation Refactor:
    • Created dedicated pages for github/user, github/app, and github/oidc.
    • Integrated Mermaid diagrams for authentication flows and architecture.
    • Updated usage.mdx to link to new pages and deduplicate OIDC content.
  • Provider Kinds: Introduced constants (KindUser, KindApp, KindOIDC) for all GitHub providers.
  • Test Coverage: Achieved 80.7% statement coverage across new provider implementations.

closes #XXX (Placeholder for actual issue number)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added GitHub User authentication via OAuth Device Flow for personal development workflows
    • Added GitHub App authentication via JWT for automation and CI/CD pipelines
    • Added atmos auth git-credential command for seamless Git integration
    • Added atmos auth logout command to revoke GitHub credentials
    • Improved authentication success message styling
  • Documentation

    • Added comprehensive GitHub authentication provider guides
    • Updated authentication usage documentation
  • Chores

    • Updated dependencies to support JWT signing
    • Added implementation tracking documentation

@osterman osterman requested a review from a team as a code owner October 20, 2025 20:01
@github-actions github-actions bot added the size/xl Extra large size PR label Oct 20, 2025
@mergify
Copy link

mergify bot commented Oct 20, 2025

Warning

This PR exceeds the recommended limit of 1,000 lines.

Large PRs are difficult to review and may be rejected due to their size.

Please verify that this PR does not address multiple issues.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Warning

Rate limit exceeded

@osterman has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 20 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between cd7cc6c and 70c0fb2.

📒 Files selected for processing (18)
  • .github/workflows/test-github-oidc.yml (1 hunks)
  • cmd/auth_git_credential.go (1 hunks)
  • cmd/auth_login.go (2 hunks)
  • cmd/auth_logout.go (1 hunks)
  • debug_plan_diff_windows.md (0 hunks)
  • errors/errors.go (1 hunks)
  • pkg/auth/identities/github/token.go (1 hunks)
  • pkg/auth/providers/github/app.go (1 hunks)
  • pkg/auth/providers/github/constants.go (1 hunks)
  • pkg/auth/providers/github/device_flow_client.go (1 hunks)
  • pkg/auth/providers/github/user.go (1 hunks)
  • pkg/auth/providers/github/user_test.go (1 hunks)
  • pkg/auth/providers/github/web_flow_client.go (1 hunks)
  • tests/test-cases/auth-github-oidc/README.md (1 hunks)
  • tests/test-cases/auth-github-oidc/atmos.yaml (1 hunks)
  • tests/test-cases/auth-github-oidc/stacks/example.yaml (1 hunks)
  • website/blog/2025-10-20-github-authentication-providers.md (1 hunks)
  • website/docs/cli/commands/auth/providers/github-user.mdx (1 hunks)
📝 Walkthrough

Walkthrough

This PR implements GitHub authentication with OAuth Device Flow (user authentication) and JWT-based GitHub App flows, adding new CLI commands for git-credential helper and logout, creating provider and identity implementations, defining new credential types, integrating storage support, and providing comprehensive documentation and tests.

Changes

Cohort / File(s) Summary
Documentation & Planning
DOCUMENTATION_STRUCTURE_PROPOSAL.md, GITHUB_IDENTITY_PLAN.md, GITHUB_MERMAID_DIAGRAMS.md, IMPLEMENTATION_STATUS.md, IMPLEMENTATION_COMPLETE.md
New planning and design documentation for GitHub authentication structure, implementation plan with phases, architecture diagrams, and completion status tracking.
GitHub Provider Implementation
pkg/auth/providers/github/constants.go, pkg/auth/providers/github/device_flow_client.go, pkg/auth/providers/github/user.go, pkg/auth/providers/github/app.go, pkg/auth/providers/github/oidc.go
New provider kinds (github/user, github/app), Device Flow client implementation for OAuth polling, user provider with Device Flow support, GitHub App provider with JWT generation, and OIDC refactor to use constants.
Provider Tests
pkg/auth/providers/github/user_test.go, pkg/auth/providers/github/app_test.go, pkg/auth/providers/github/mock_device_flow_client_test.go, pkg/auth/providers/github/oidc_test.go
Comprehensive test coverage for device flow client mocking, user provider lifecycle, GitHub App authentication and key management, credentials expiration, and environment setup.
Credential Types
pkg/auth/types/github_user_credentials.go, pkg/auth/types/github_app_credentials.go
New credential types with expiration tracking, environment variable population (GITHUB_TOKEN, GH_TOKEN), and whoami info building.
Identity Implementation
pkg/auth/identities/github/token.go
GitHub token identity supporting github/token kind with provider credential pass-through and environment variable mapping.
Factory & Storage
pkg/auth/factory/factory.go, pkg/auth/credentials/store.go
Factory registration for new GitHub providers and identities; keyring store support for GitHubUserCredentials and GitHubAppCredentials persistence.
CLI Commands
cmd/auth_login.go, cmd/auth_logout.go, cmd/auth_git_credential.go
Enhanced login output formatting with styled UI; new logout command with identity and all-logout support; new git-credential helper for Git integration.
Website Documentation
website/docs/cli/commands/auth/providers/github-user.mdx, website/docs/cli/commands/auth/providers/github-app.mdx, website/docs/cli/commands/auth/providers/github-oidc.mdx, website/docs/cli/commands/auth/usage.mdx
New provider-specific documentation for Device Flow (github/user), JWT-based (github/app), and OIDC flows; updated usage overview with provider grouping.
PRD & Dependencies
docs/prd/github-authentication-providers.md, go.mod
Product requirements document for GitHub authentication; Go toolchain bump to 1.25.1 and addition of JWT signing dependency.
Test Snapshots
tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden
Updated command help text to include new git-credential and logout subcommands.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as Atmos CLI
    participant DeviceFlow as Device Flow<br/>Client
    participant GitHub as GitHub API
    participant Store as Credential<br/>Store
    
    User->>CLI: atmos auth login
    CLI->>DeviceFlow: StartDeviceFlow()
    DeviceFlow->>GitHub: POST /device/code
    GitHub-->>DeviceFlow: device_code, user_code, verification_uri
    DeviceFlow-->>CLI: DeviceFlowResponse
    CLI->>User: Display user_code & verification_uri
    
    User->>GitHub: Visit verification_uri<br/>Enter user_code
    
    CLI->>DeviceFlow: PollForToken(device_code)
    loop Poll with backoff
        DeviceFlow->>GitHub: POST /token (with device_code)
        alt Authorization pending
            GitHub-->>DeviceFlow: authorization_pending
        else Token ready
            GitHub-->>DeviceFlow: access_token, expires_in
            DeviceFlow-->>CLI: token
        end
    end
    
    CLI->>Store: Store credentials
    Store-->>CLI: Success
    CLI->>User: Success message
Loading
sequenceDiagram
    participant App as Atmos CLI
    participant GitHub as GitHub API
    participant Store as Credential<br/>Store
    
    App->>App: Load GitHub App config<br/>(app_id, installation_id, private_key)
    App->>App: Generate JWT<br/>(RS256, 10-min expiry)
    App->>GitHub: GET /app/installations/{installation_id}/access_tokens<br/>with JWT + permissions
    GitHub-->>App: access_token, expires_at (1-hour)
    App->>Store: Store credentials<br/>(token, app_id, installation_id, expiry)
    Store-->>App: Success
    App->>App: Use token in requests
    
    Note over App: Token auto-refreshes<br/>on next command if expired
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The implementation spans multiple authentication flows (Device Flow, JWT, OIDC refactor), introduces new credential types and storage integration, adds CLI commands with UI components, and includes substantial test coverage across provider, identity, and credential lifecycles. While the changes are well-organized by cohort and documentation is thorough, each authentication provider requires independent reasoning around token lifecycle, error handling, and security considerations (key management, token expiration, scope validation). The heterogeneity of changes—mixing providers, identities, types, factories, CLI, and tests—requires distributed review attention across distinct subsystems.

Possibly related PRs

  • Atmos Auth Implementation #1475 — Directly overlaps in the auth subsystem, implementing and modifying GitHub providers, auth CLI commands, schema/auth types, and provider/identity code paths.

Suggested reviewers

  • aknysh
  • Benbentwo
  • milldr

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Update auth docs and implement GitHub providers" directly reflects the two major aspects of this changeset. The documentation updates are evident across multiple new files (DOCUMENTATION_STRUCTURE_PROPOSAL.md, GITHUB_IDENTITY_PLAN.md, GITHUB_MERMAID_DIAGRAMS.md, and new provider MDX documentation pages). The GitHub provider implementation is clearly present with new provider code (user.go, app.go, constants.go, device_flow_client.go), credential types, CLI commands (auth_git_credential.go, auth_logout.go), factory updates, and comprehensive test coverage. The title is specific and clear enough that a teammate scanning history would immediately understand this PR concerns GitHub authentication infrastructure and documentation, without being misleading or overly vague.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/auth/providers/github/oidc.go (2)

97-103: Prefer ATMOS_ env overrides with viper.BindEnv.

Per guidelines, bind an ATMOS_ alternative and prefer it when present.

Suggested diffs:

 func (p *oidcProvider) isGitHubActions() bool {
-	if err := viper.BindEnv("github.actions", "GITHUB_ACTIONS"); err != nil {
+	if err := viper.BindEnv("github.actions", "ATMOS_GITHUB_ACTIONS"); err != nil {
 		log.Trace("Failed to bind github.actions environment variable", "error", err)
 	}
-	return viper.GetString("github.actions") == "true"
+	if v := viper.GetString("github.actions"); v != "" {
+		return v == "true"
+	}
+	_ = viper.BindEnv("github.actions", "GITHUB_ACTIONS")
+	return viper.GetString("github.actions") == "true"
 }
@@
 func (p *oidcProvider) requestParams() (string, string, error) {
-	if err := viper.BindEnv("github.oidc.request_token", "ACTIONS_ID_TOKEN_REQUEST_TOKEN"); err != nil {
+	if err := viper.BindEnv("github.oidc.request_token", "ATMOS_GITHUB_OIDC_REQUEST_TOKEN"); err != nil {
 		log.Trace("Failed to bind github.oidc.request_token environment variable", "error", err)
 	}
-	token := viper.GetString("github.oidc.request_token")
+	if viper.GetString("github.oidc.request_token") == "" {
+		_ = viper.BindEnv("github.oidc.request_token", "ACTIONS_ID_TOKEN_REQUEST_TOKEN")
+	}
+	token := viper.GetString("github.oidc.request_token")
@@
-	if err := viper.BindEnv("github.oidc.request_url", "ACTIONS_ID_TOKEN_REQUEST_URL"); err != nil {
+	if err := viper.BindEnv("github.oidc.request_url", "ATMOS_GITHUB_OIDC_REQUEST_URL"); err != nil {
 		log.Trace("Failed to bind github.oidc.request_url environment variable", "error", err)
 	}
-	requestURL := viper.GetString("github.oidc.request_url")
+	if viper.GetString("github.oidc.request_url") == "" {
+		_ = viper.BindEnv("github.oidc.request_url", "ACTIONS_ID_TOKEN_REQUEST_URL")
+	}
+	requestURL := viper.GetString("github.oidc.request_url")
@@
 func (p *oidcProvider) resolveJWT(ctx context.Context, requestURL, token, aud string) (string, error) {
-	if err := viper.BindEnv("github.oidc.id_token", "ACTIONS_ID_TOKEN"); err != nil {
+	if err := viper.BindEnv("github.oidc.id_token", "ATMOS_GITHUB_OIDC_ID_TOKEN"); err != nil {
 		log.Trace("Failed to bind github.oidc.id_token environment variable", "error", err)
 	}
-	if jwt := viper.GetString("github.oidc.id_token"); jwt != "" {
+	if jwt := viper.GetString("github.oidc.id_token"); jwt != "" {
 		return jwt, nil
 	}
+	_ = viper.BindEnv("github.oidc.id_token", "ACTIONS_ID_TOKEN")
+	if jwt := viper.GetString("github.oidc.id_token"); jwt != "" {
+		return jwt, nil
+	}

Also applies to: 106-123, 136-149


58-95: Add perf.Track to Authenticate (and constructor) per perf guidelines.

Authenticate is a public entrypoint and networked; add defer perf.Track(...) with package-qualified name and atmosConfig (or nil) immediately at function start, followed by a blank line.

🧹 Nitpick comments (35)
pkg/auth/providers/github/keychain_store_test.go (2)

12-47: Stabilize tests with go-keyring MockInit to avoid flaky OS prompts.

For unit-style tests (GetNotFound/DeleteNotFound), initialize the in-memory keyring to avoid platform dependencies and CI flakiness.

 func TestOSKeychainStore_GetNotFound(t *testing.T) {
-	if testing.Short() {
-		t.Skip("Skipping keychain integration test in short mode")
-	}
+	keyring.MockInit()
@@
 func TestOSKeychainStore_DeleteNotFound(t *testing.T) {
-	if testing.Short() {
-		t.Skip("Skipping keychain integration test in short mode")
-	}
+	keyring.MockInit()

Keep TestOSKeychainStore_Integration as an opt-in integration test (skipped in short mode). Based on learnings.

Also applies to: 49-68, 70-89


22-25: Handle cleanup errors to satisfy linters.

Explicitly handle Delete errors or annotate with //nolint:errcheck and a reason to pass golangci-lint.

-// Clean up any existing test data.
-_ = keyring.Delete(service, account)
-defer keyring.Delete(service, account)
+// Clean up any existing test data.
+if err := keyring.Delete(service, account); err != nil && !errors.Is(err, keyring.ErrNotFound) {
+	t.Logf("pre-cleanup: %v", err)
+}
+defer func() {
+	if err := keyring.Delete(service, account); err != nil && !errors.Is(err, keyring.ErrNotFound) {
+		t.Logf("post-cleanup: %v", err)
+	}
+}()
pkg/auth/providers/github/keychain_store.go (3)

10-15: Fix comment punctuation to satisfy godot.

Ensure each bullet ends with a period.

-// Uses github.com/zalando/go-keyring which provides cross-platform support:
-// - macOS: Keychain Access
-// - Windows: Credential Manager
-// - Linux: Secret Service (GNOME Keyring, KWallet).
+// Uses github.com/zalando/go-keyring which provides cross-platform support.
+// - macOS: Keychain Access.
+// - Windows: Credential Manager.
+// - Linux: Secret Service (GNOME Keyring, KWallet).

35-42: Include service/account context in Set error for parity.

Mirror Get/Delete context in Set for better diagnostics.

-	if err != nil {
-		return fmt.Errorf("failed to store token in %s keychain: %w", runtime.GOOS, err)
-	}
+	if err != nil {
+		return fmt.Errorf("failed to store token in %s keychain (service=%s account=%s): %w", runtime.GOOS, service, account, err)
+	}

15-20: Consider exposing DeleteAll to support ‘logout all’.

go-keyring v0.2.6 provides DeleteAll; offering it via KeychainStore enables “atmos auth logout” to wipe all entries for a service without knowing accounts. Optional but handy.

Example (requires interface change):

  • Add: DeleteAll(service string) error
  • Impl: return keyring.DeleteAll(service)
GITHUB_MERMAID_DIAGRAMS.md (1)

241-241: Wrap the bare URL in a markdown link.

The bare URL should be formatted as a markdown link for better practices.

Apply this change:

-1. **Mermaid Live Editor**: https://mermaid.live - paste and preview
+1. **Mermaid Live Editor**: [https://mermaid.live](https://mermaid.live) - paste and preview
IMPLEMENTATION_STATUS.md (1)

195-229: Consider adding language identifiers to code blocks.

The code blocks showing file listings would be clearer with language identifiers. This is optional for planning docs but improves readability.

For example:

-```
+```text
 pkg/auth/providers/github/user.go                    # 248 lines
 ...
docs/prd/github-authentication-providers.md (1)

194-231: Consider adding language identifiers to ASCII diagram blocks.

The architecture diagrams would be clearer with a text language identifier. This helps readers and tools understand the content type.

For example:

-```
+```text
 ┌─────────────────────────────────────────────────────────────┐
 │                    Atmos CLI                                 │
 ...
website/docs/cli/commands/auth/usage.mdx (2)

252-274: Tighten GitHub sections with tiny clarifications.

  • Consider noting default token lifetimes inline: user (~8h), app (~1h).
  • For the OIDC example (Line 304), keep audience as shown and add a one‑liner that AWS roles typically require "sts.amazonaws.com".
  • Optional: Add a short example showing how to wire the git credential helper to pair with these providers.

I can draft the extra lines if you want.

Also applies to: 275-294, 296-305


358-364: Remove duplicate dotenv example line.

Two identical lines are listed.

- atmos auth env --format dotenv
- atmos auth env --format dotenv
+ atmos auth env --format dotenv
cmd/auth_git_credential.go (3)

17-43: Harden Cobra command ergonomics.

  • Hide helper from normal help and silence usage on errors.
 var authGitCredentialCmd = &cobra.Command{
   Use:   "git-credential",
   Short: "Git credential helper for GitHub authentication",
   Long: `Act as a Git credential helper for GitHub authentication.
@@
   ValidArgs:          []string{"get", "store", "erase"},
   DisableFlagParsing: false,
   FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
   RunE:               executeGitCredentialCommand,
+  SilenceUsage:       true,
+  Hidden:             true,
 }

71-76: Tighten host check to avoid false positives.

Avoid matching hosts like notgithub.com.

- if !strings.Contains(input["host"], "github.com") {
+ host := input["host"]
+ if host != "github.com" && host != "api.github.com" && host != "gist.github.com" {
   // Return empty response for non-GitHub hosts.
   return nil
 }

Please confirm if you want to support additional GitHub subdomains (enterprise is out of scope for now).


77-82: Avoid full stack processing for this helper.

No stacks needed; skip for speed.

- atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true)
+ atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false)
GITHUB_IDENTITY_PLAN.md (1)

370-386: Polish markdown for easier reading and linting.

  • Add languages to fenced code blocks (yaml, bash, go).
  • Replace bare URLs with markdown links.
  • Deduplicate repeated headings.

Happy to push a quick cleanup commit if desired.

Also applies to: 404-420, 523-556

cmd/auth_logout.go (2)

3-14: Sort stdlib imports alphabetically.

Keep stdlib group alpha per guidelines.

 import (
-  "context"
-  "os"
-  "fmt"
+  "context"
+  "fmt"
+  "os"

16-44: Cobra ergonomics: silence usage.

Prevents noisy usage on expected errors.

 var authLogoutCmd = &cobra.Command{
   Use:   "logout",
   Short: "Log out and clear cached credentials",
@@
   RunE:               executeLogoutCommand,
+  SilenceUsage:       true,
 }
pkg/auth/providers/github/device_flow_client_test.go (1)

14-26: Nice coverage. Two optional nits.

  • Add t.Parallel() at the start of tests to speed execution.
  • Consider generating a mock for the keychain interface via mockgen to align with repo conventions.

No blockers.

Also applies to: 27-64, 65-106, 107-132, 133-158, 159-171, 173-189, 191-205, 206-219, 221-237, 239-264, 265-293

pkg/auth/providers/github/app.go (2)

231-239: Use bytes.NewReader and drop custom reader.

Simplifies code and reduces surface area.

- var body io.Reader
+ var body io.Reader
  if len(requestBody) > 0 {
    jsonData, err := json.Marshal(requestBody)
    if err != nil {
      return "", time.Time{}, fmt.Errorf("failed to marshal request body: %w", err)
    }
-   body = &readSeeker{data: jsonData}
+   body = bytes.NewReader(jsonData)
  }
@@
-// readSeeker is a helper to make []byte compatible with io.Reader.
-type readSeeker struct {
-  data []byte
-  pos  int
-}
-
-func (r *readSeeker) Read(p []byte) (n int, err error) {
-  if r.pos >= len(r.data) {
-    return 0, io.EOF
-  }
-  n = copy(p, r.data[r.pos:])
-  r.pos += n
-  return n, nil
-}
+// (reader helper removed; bytes.NewReader used instead)

Also applies to: 293-306


245-248: Set a User-Agent header.

GitHub API prefers a UA; include Atmos version if available.

 req.Header.Set("Authorization", "Bearer "+jwtToken)
 req.Header.Set("Accept", "application/vnd.github+json")
 req.Header.Set("Content-Type", "application/json")
+req.Header.Set("User-Agent", "Atmos (Cloud Posse; +https://atmos.tools)")
pkg/auth/providers/github/app_test.go (4)

223-233: Make HTTP rewrite robust and keep timeouts.

String-slicing server.URL is brittle and the new http.Client loses the default timeout. Prefer parsing the URL and preserving a timeout.

Apply:

+   "net/url"
@@
-   appProv.httpClient = &http.Client{
-       Transport: &roundTripperFunc{
-           fn: func(req *http.Request) (*http.Response, error) {
-               // Rewrite URL to point to test server.
-               req.URL.Scheme = "http"
-               req.URL.Host = server.URL[7:] // Remove "http://".
-               return http.DefaultTransport.RoundTrip(req)
-           },
-       },
-   }
+   srvURL, _ := url.Parse(server.URL)
+   appProv.httpClient = &http.Client{
+       Timeout: 30 * time.Second,
+       Transport: &roundTripperFunc{
+           fn: func(req *http.Request) (*http.Response, error) {
+               req.URL.Scheme = srvURL.Scheme
+               req.URL.Host = srvURL.Host
+               return http.DefaultTransport.RoundTrip(req)
+           },
+       },
+   }

254-270: Also assert repositories are forwarded.

You already verify permissions; add a check that repositories are included when specified.

Apply:

     var reqBody map[string]interface{}
     json.NewDecoder(r.Body).Decode(&reqBody)

     permissions, ok := reqBody["permissions"].(map[string]interface{})
     assert.True(t, ok)
     assert.Equal(t, "read", permissions["contents"])
+
+    repos, ok := reqBody["repositories"].([]interface{})
+    assert.True(t, ok)
+    assert.ElementsMatch(t, []interface{}{"repo1"}, repos)

25-41: Add a PKCS#8 private key test.

Provider likely supports PKCS1 and PKCS8. Add a PKCS8 case to avoid regressions.

Example to append near file end:

+func TestAppProvider_LoadPrivateKey_PKCS8(t *testing.T) {
+    key, err := rsa.GenerateKey(rand.Reader, 2048)
+    require.NoError(t, err)
+    pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(key)
+    require.NoError(t, err)
+    pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Bytes})
+
+    dir := t.TempDir()
+    keyPath := filepath.Join(dir, "key.pem")
+    require.NoError(t, os.WriteFile(keyPath, pemBytes, 0600))
+
+    cfg := &schema.Provider{
+        Kind: KindApp,
+        Spec: map[string]interface{}{
+            "app_id":           "12345",
+            "installation_id":  "67890",
+            "private_key_path": keyPath,
+        },
+    }
+    p, err := NewAppProvider("github-app", cfg)
+    require.NoError(t, err)
+    assert.NotNil(t, p)
+}

43-160: Parallelize table tests.

Call t.Parallel() inside the t.Run to speed up and isolate subtests.

 for _, tt := range tests {
     t.Run(tt.name, func(t *testing.T) {
+        t.Parallel()
         provider, err := NewAppProvider(tt.provName, tt.config)
         ...
     })
 }
pkg/auth/providers/github/user_test.go (3)

18-73: Add test for invalid provider kind.

Constructor should reject non-github/user kinds.

Append:

+func TestNewUserProvider_InvalidKind(t *testing.T) {
+    cfg := &schema.Provider{Kind: "github/app", Spec: map[string]interface{}{"client_id": "x"}}
+    p, err := NewUserProvider("github-user", cfg)
+    assert.Error(t, err)
+    assert.Nil(t, p)
+    assert.ErrorIs(t, err, errUtils.ErrInvalidProviderKind)
+}

18-73: Assert optional fields parsing.

Coverage for token_lifetime and keychain_service improves confidence.

Append:

+func TestNewUserProvider_OptionalFields(t *testing.T) {
+    cfg := &schema.Provider{
+        Kind: KindUser,
+        Spec: map[string]interface{}{
+            "client_id":       "id",
+            "token_lifetime":  "6h",
+            "keychain_service":"atmos-github-work",
+        },
+    }
+    p, err := NewUserProvider("github-user", cfg)
+    require.NoError(t, err)
+    up := p.(*userProvider)
+    assert.Equal(t, 6*time.Hour, up.tokenLifetime)
+    assert.Equal(t, "atmos-github-work", up.keychainSvc)
+}

95-133: Parallelize tests.

Add t.Parallel() to top-level tests and inside t.Run where applicable to speed up CI and catch racey tests.

Example:

 func TestUserProvider_Authenticate_WithCachedToken(t *testing.T) {
+   t.Parallel()
    ctrl := gomock.NewController(t)
    ...
 }

Also applies to: 134-191, 192-227, 229-287, 289-318, 320-353, 355-369, 370-383, 385-404, 406-416

SUMMARY.md (2)

236-253: Tighten security wording.

“Never expose in logs or errors” — consider “Do not include raw tokens/keys in logs or error messages.”

-   - Never expose in logs or errors
+   - Do not include raw tokens or private keys in logs or error messages.

281-286: Update SUMMARY.md to include pinned dependency versions.

The go.mod file pins github.com/suzuki-shunsuke/ghtkn to v0.2.2 and github.com/golang-jwt/jwt/v5 to v5.3.0. Update the dependency list in SUMMARY.md to match:

  • github.com/suzuki-shunsuke/ghtkn v0.2.2 - Device Flow (already added)
  • github.com/golang-jwt/jwt/v5 v5.3.0 - JWT signing (to be added)

This ensures the planning document stays synchronized with the actual pinned versions.

website/docs/cli/commands/auth/providers/github-user.mdx (3)

199-206: Add language to output code fence.

Silence MD040 by marking the block as text.

-**Output:**
-```
+**Output:**
+```text
 To authenticate with GitHub:
 1. Visit: https://github.com/login/device
 2. Enter code: ABCD-1234
@@
 ✓ Successfully authenticated

---

`367-374`: **Deduplicate “Related” sections.**

There are two “Related” headings. Keep one and merge links.


- Remove the later “Related” or rename it to “More resources,” ensuring links are consolidated.


Also applies to: 834-841

---

`183-191`: **Shell commands: drop leading $ for lint clarity.**

MD014 flags `$` prefixes without showing output. Use plain commands or mark as shell-session with outputs.


```diff
-git config --global credential.helper '!atmos auth git-credential'
+git config --global credential.helper '!atmos auth git-credential'

And prefer fenced language bash for commands and text/console for outputs.

DOCUMENTATION_STRUCTURE_PROPOSAL.md (1)

112-224: Add fenced languages in the template.

A few example fences in the template lack a language, tripping MD040.

  • Use yaml, bash, mermaid, text appropriately in all template examples.
pkg/auth/providers/github/device_flow_client.go (1)

117-121: Use server-provided polling interval (avoid rate limiting).

You decode Interval but never use it; PollForToken always ticks at defaultInterval. Persist interval on StartDeviceFlow and use it when polling.

Apply:

 type realDeviceFlowClient struct {
   clientID      string
   scopes        []string
   keychainSvc   string
   httpClient    *http.Client
   keychainStore KeychainStore
+  pollInterval  time.Duration
 }
 
 func NewDeviceFlowClient(clientID string, scopes []string, keychainSvc string) DeviceFlowClient {
   return &realDeviceFlowClient{
     clientID:    clientID,
     scopes:      scopes,
     keychainSvc: keychainSvc,
     httpClient: &http.Client{
       Timeout: 30 * time.Second,
     },
-    keychainStore: newOSKeychainStore(),
+    keychainStore: newOSKeychainStore(),
+    pollInterval:  time.Duration(defaultInterval) * time.Second,
   }
 }
 
 // StartDeviceFlow initiates the Device Flow and returns device/user codes.
 func (c *realDeviceFlowClient) StartDeviceFlow(ctx context.Context) (*DeviceFlowResponse, error) {
@@
   // Set default interval if not provided.
   if result.Interval == 0 {
     result.Interval = defaultInterval
   }
+  c.pollInterval = time.Duration(result.Interval) * time.Second
 
   return &result, nil
 }
 
 // PollForToken polls GitHub for the access token after user authorization.
 func (c *realDeviceFlowClient) PollForToken(ctx context.Context, deviceCode string) (string, error) {
   defer perf.Track(nil, "github.realDeviceFlowClient.PollForToken")()
 
-  ticker := time.NewTicker(time.Duration(defaultInterval) * time.Second)
+  ticker := time.NewTicker(c.pollInterval)
   defer ticker.Stop()

Also applies to: 30-36, 49-60, 105-110

pkg/auth/providers/github/user.go (2)

59-61: Use the constant for kind checks.

Prefer KindUser over the raw string.

-	if config.Kind != "github/user" {
+	if config.Kind != KindUser {

89-93: Don’t silently ignore invalid token_lifetime.

If ParseDuration fails, return an error so misconfig doesn’t silently fall back to default.

-	if lifetimeStr, ok := config.Spec["token_lifetime"].(string); ok && lifetimeStr != "" {
-		if duration, err := time.ParseDuration(lifetimeStr); err == nil {
-			tokenLifetime = duration
-		}
-	}
+	if lifetimeStr, ok := config.Spec["token_lifetime"].(string); ok && lifetimeStr != "" {
+		duration, err := time.ParseDuration(lifetimeStr)
+		if err != nil {
+			return nil, fmt.Errorf("%w: invalid token_lifetime %q: %v", errUtils.ErrInvalidProviderConfig, lifetimeStr, err)
+		}
+		tokenLifetime = duration
+	}

Comment on lines +100 to +106
// Check if identity is a GitHub provider.
providerKind, err := authManager.GetProviderKindForIdentity(identityName)
if err != nil || (providerKind != "github/user" && providerKind != "github/app") {
// Not a GitHub identity, return empty.
return nil
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Prefer provider kind constants (if exported).

Using string literals risks drift.

If feasible, import the provider kind constants (e.g., githubprov.KindUser, githubprov.KindApp) and compare against those. Otherwise, keep as-is but consider centralizing kinds in a shared package.


🏁 Script executed:

#!/bin/bash
# Find where provider kind constants live to avoid importing provider internals into cmd.
rg -nP --type=go -C2 'Kind(User|App|OIDC)\s*=\s*"github/' pkg | sed -n '1,120p'

Length of output: 710


Use provider kind constants from pkg/auth/providers/github.

The constants KindUser and KindApp are already exported in pkg/auth/providers/github/constants.go. Replace the string literals "github/user" and "github/app" with these constants to centralize provider kinds and prevent drift. This is a straightforward import and refactor at lines 100-106.

🤖 Prompt for AI Agents
In cmd/auth_git_credential.go around lines 100 to 106, the code uses string
literals "github/user" and "github/app" to check provider kind; replace those
literals with the exported constants from pkg/auth/providers/github (KindUser
and KindApp), add the import for pkg/auth/providers/github, and update the
conditional to compare providerKind against github.KindUser and github.KindApp
so provider kinds are centralized and less error-prone.

Comment on lines +107 to +118
// Authenticate and get credentials.
ctx := context.Background()
whoami, err := authManager.Authenticate(ctx, identityName)
if err != nil {
return fmt.Errorf("authentication failed: %w", err)
}

// Extract GitHub token from environment variables.
token, ok := whoami.Environment["GITHUB_TOKEN"]
if !ok || token == "" {
return fmt.Errorf("%w: no GITHUB_TOKEN in authentication result", errUtils.ErrAuthenticationFailed)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Wrap with sentinel error consistently.

Aligns with errors policy.

- whoami, err := authManager.Authenticate(ctx, identityName)
- if err != nil {
-   return fmt.Errorf("authentication failed: %w", err)
- }
+ whoami, err := authManager.Authenticate(ctx, identityName)
+ if err != nil {
+   return fmt.Errorf("%w: %v", errUtils.ErrAuthenticationFailed, err)
+ }
@@
- if !ok || token == "" {
-   return fmt.Errorf("%w: no GITHUB_TOKEN in authentication result", errUtils.ErrAuthenticationFailed)
- }
+ if !ok || token == "" {
+   return fmt.Errorf("%w: no GITHUB_TOKEN in authentication result", errUtils.ErrAuthenticationFailed)
+ }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cmd/auth_git_credential.go around lines 107 to 118, the Authenticate error
return is not wrapped with the sentinel errUtils.ErrAuthenticationFailed while
the later GITHUB_TOKEN check correctly uses the sentinel; change the
Authenticate failure return to wrap and return the sentinel error (preserving
the original error as context) so both failure paths consistently use
errUtils.ErrAuthenticationFailed with the underlying error included.

Comment on lines +45 to +77
// executeLogoutCommand performs logout and credential cleanup.
func executeLogoutCommand(cmd *cobra.Command, args []string) error {
// Load atmos configuration.
atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true)
if err != nil {
return fmt.Errorf("failed to load atmos config: %w", err)
}

// Create auth manager.
authManager, err := createAuthManager(&atmosConfig.Auth)
if err != nil {
return fmt.Errorf("failed to create auth manager: %w", err)
}

// Check if logout all.
logoutAll, _ := cmd.Flags().GetBool("all")

if logoutAll {
return logoutAllIdentities(authManager)
}

// Get identity from flag or use default.
identityName, _ := cmd.Flags().GetString("identity")
if identityName == "" {
defaultIdentity, err := authManager.GetDefaultIdentity()
if err != nil {
return fmt.Errorf("%w: no default identity configured and no identity specified: %v", errUtils.ErrNoDefaultIdentity, err)
}
identityName = defaultIdentity
}

return logoutIdentity(authManager, identityName)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Add perf.Track and strengthen typing + behavior.

  • Track perf on the command and helpers.
  • Use a concrete AuthManager interface instead of interface{}.
  • Implement provider‑specific cleanup (keychain delete) before shipping.
 func executeLogoutCommand(cmd *cobra.Command, args []string) error {
+  defer perf.Track(nil, "cmd.authLogout.executeLogoutCommand")()
@@
- return logoutIdentity(authManager, identityName)
+ return logoutIdentity(authManager, identityName)
 }
 
-// logoutIdentity logs out a single identity.
-func logoutIdentity(authManager interface{}, identityName string) error {
+// logoutIdentity logs out a single identity.
+func logoutIdentity(authManager types.AuthManager, identityName string) error {
+  defer perf.Track(nil, "cmd.authLogout.logoutIdentity")()
   ctx := context.Background()
@@
- log.Info("Logging out from identity", "identity", identityName)
+ log.Info("Logging out from identity", "identity", identityName)
+ // TODO: call provider-specific cleanup via authManager (e.g., delete keychain entries for github/user).
@@
   return nil
 }
 
-// logoutAllIdentities logs out all configured identities.
-func logoutAllIdentities(authManager interface{}) error {
+// logoutAllIdentities logs out all configured identities.
+func logoutAllIdentities(authManager types.AuthManager) error {
+  defer perf.Track(nil, "cmd.authLogout.logoutAllIdentities")()
@@
   return nil
 }

If types.AuthManager is not available publicly, define a minimal local interface in this file exposing the needed methods (e.g., ListIdentities, Logout(identity)).

Also applies to: 79-105, 106-121


🏁 Script executed:

#!/bin/bash
# Locate the concrete AuthManager type and any existing Logout/List APIs.
rg -nP --type=go -C2 '\btype\s+.*AuthManager\b|func\s+\(.*\)\s+Logout\(|ListIdentit' pkg internal cmd

Length of output: 3788


🏁 Script executed:

#!/bin/bash
# Get the full AuthManager interface definition
rg -nP --type=go -A20 'type AuthManager interface \{' pkg/auth/types/interfaces.go

Length of output: 947


🏁 Script executed:

#!/bin/bash
# Inspect the current state of logoutIdentity and logoutAllIdentities
rg -nP --type=go -B2 -A12 'func logout(Identity|All)' cmd/auth_logout.go

Length of output: 1307


🏁 Script executed:

#!/bin/bash
# Check if Logout is defined anywhere in AuthManager or its implementations
rg -nP --type=go 'Logout\(' pkg/auth/types/ pkg/auth/manager.go

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for Logout in manager.go and executeLogoutCommand instrumentation status
rg -nP --type=go 'func.*Logout|executeLogoutCommand' pkg/auth/manager.go cmd/auth_logout.go

Length of output: 241


🏁 Script executed:

#!/bin/bash
# Check executeLogoutCommand definition to see current state
cat cmd/auth_logout.go | head -80 | tail -40

Length of output: 1271



Add perf.Track instrumentation and fix interface typing for logout functions.

The interface{} usage in logoutIdentity and logoutAllIdentities should be replaced with a concrete type. However, types.AuthManager currently lacks a Logout method. Two approaches work:

  1. Add Logout(ctx context.Context, identityName string) error to the AuthManager interface in pkg/auth/types/interfaces.go, then implement it in pkg/auth/manager.go.
  2. Define a minimal local interface in cmd/auth_logout.go with only the methods needed for logout (e.g., ListIdentities, GetProviderForIdentity, provider-specific logout calls).

Additionally:

  • Add defer perf.Track(atmosConfig, "cmd.authLogout.executeLogoutCommand")() to executeLogoutCommand (line 46) with a blank line after.
  • Add defer perf.Track(nil, "cmd.authLogout.logoutIdentity")() to logoutIdentity (line 80) with a blank line after.
  • Add defer perf.Track(nil, "cmd.authLogout.logoutAllIdentities")() to logoutAllIdentities (line 107) with a blank line after.
  • Implement provider-specific cleanup (keychain deletion) rather than placeholder—this is blocking production readiness.

Comment on lines +28 to +30
// realDeviceFlowClient implements the DeviceFlowClient interface for actual GitHub API calls.
// This implementation is inspired by ghtkn: https://github.com/suzuki-shunsuke/ghtkn
type realDeviceFlowClient struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

godot: add trailing period.

Add a period to the “Inspired by …” comment to satisfy godot.

-// This implementation is inspired by ghtkn: https://github.com/suzuki-shunsuke/ghtkn
+// This implementation is inspired by ghtkn: https://github.com/suzuki-shunsuke/ghtkn.
🤖 Prompt for AI Agents
pkg/auth/providers/github/device_flow_client.go around lines 28 to 30: the
comment ending "inspired by ghtkn: https://github.com/suzuki-shunsuke/ghtkn" is
missing a trailing period; update the comment to add a final period after the
URL so the sentence ends with proper punctuation.

Comment on lines +22 to +33
// Get retrieves a token from the OS keychain.
func (s *osKeychainStore) Get(service string, account string) (string, error) {
token, err := keyring.Get(service, account)
if err != nil {
// go-keyring returns ErrNotFound on all platforms when item doesn't exist.
if err == keyring.ErrNotFound {
return "", fmt.Errorf("token not found in %s keychain for service=%s account=%s", runtime.GOOS, service, account)
}
return "", fmt.Errorf("failed to get token from %s keychain: %w", runtime.GOOS, err)
}
return token, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Adopt a static sentinel for “not found” and wrap errors accordingly.

Per guidelines, return a static error (from errors/errors.go) and wrap with context; avoid forcing callers to string-compare. Use errors.Is for keyring.ErrNotFound.

Proposed diff (assumes new sentinel errUtils.ErrCredentialNotFound):

@@
-import (
-	"fmt"
-	"runtime"
-
-	"github.com/zalando/go-keyring"
-)
+import (
+	"errors"
+	"fmt"
+	"runtime"
+
+	errUtils "github.com/cloudposse/atmos/errors"
+	"github.com/zalando/go-keyring"
+)
@@
-	if err != nil {
-		// go-keyring returns ErrNotFound on all platforms when item doesn't exist.
-		if err == keyring.ErrNotFound {
-			return "", fmt.Errorf("token not found in %s keychain for service=%s account=%s", runtime.GOOS, service, account)
-		}
-		return "", fmt.Errorf("failed to get token from %s keychain: %w", runtime.GOOS, err)
-	}
+	if err != nil {
+		// Normalize not-found to a static sentinel and wrap with context.
+		if errors.Is(err, keyring.ErrNotFound) {
+			return "", fmt.Errorf("%w: token not found in %s keychain (service=%s account=%s)", errUtils.ErrCredentialNotFound, runtime.GOOS, service, account)
+		}
+		return "", fmt.Errorf("failed to get token from %s keychain (service=%s account=%s): %w", runtime.GOOS, service, account, err)
+	}
@@
-	if err != nil {
-		// go-keyring returns ErrNotFound if item doesn't exist.
-		if err == keyring.ErrNotFound {
-			return fmt.Errorf("token not found in %s keychain for service=%s account=%s", runtime.GOOS, service, account)
-		}
-		return fmt.Errorf("failed to delete token from %s keychain: %w", runtime.GOOS, err)
-	}
+	if err != nil {
+		if errors.Is(err, keyring.ErrNotFound) {
+			return fmt.Errorf("%w: token not found in %s keychain (service=%s account=%s)", errUtils.ErrCredentialNotFound, runtime.GOOS, service, account)
+		}
+		return fmt.Errorf("failed to delete token from %s keychain (service=%s account=%s): %w", runtime.GOOS, service, account, err)
+	}

Add the sentinel in errors/errors.go:

+// ErrCredentialNotFound indicates a missing credential in a backing store.
+var ErrCredentialNotFound = errors.New("credential not found")

Also applies to: 44-55

🤖 Prompt for AI Agents
In pkg/auth/providers/github/keychain_store.go around lines 22 to 33 (and
similarly for lines 44 to 55), replace the current string-based "not found"
behavior by returning the static sentinel error errUtils.ErrCredentialNotFound
from errors/errors.go when keyring.Get (and keyring.Delete/Get equivalents)
yields keyring.ErrNotFound; detect that condition using errors.Is(err,
keyring.ErrNotFound) and for other failures wrap the original error with
fmt.Errorf("%w: <context>") to preserve cause; ensure the returned not-found
case wraps the sentinel (e.g., fmt.Errorf("%w: token not found in %s keychain
for service=%s account=%s", errUtils.ErrCredentialNotFound, runtime.GOOS,
service, account)) so callers can use errors.Is to check for
ErrCredentialNotFound.

Comment on lines +207 to +214
### Logout and Revoke Token

```shell
atmos auth logout -i my-github
```

To fully revoke the token, visit: https://github.com/settings/tokens

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix token revocation guidance (OAuth vs PAT).

Device Flow uses an OAuth App; revocation happens under Authorized OAuth Apps, not the PAT tokens page.

-To fully revoke the token, visit: https://github.com/settings/tokens
+To fully revoke the token, go to GitHub Settings → Applications → Authorized OAuth Apps and revoke the app.
+See: https://docs.github.com/apps/oauth-apps/maintaining-oauth-apps/reviewing-your-authorized-oauth-apps

🌐 Web query:

Where do users revoke OAuth Device Flow tokens on GitHub, and what is the official docs URL?

💡 Result:

Revoke location: In GitHub → your profile → Settings → Applications → Authorized OAuth Apps (select the app → Revoke). Device-flow (OAuth) tokens are revoked there the same as other OAuth app tokens. [1]

Official docs: "Authorizing OAuth apps" — https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps. [2]

Sources:
[1] Reviewing your authorized OAuth apps (GitHub Docs).
[2] Authorizing OAuth apps — Device flow (GitHub Docs).


Update token revocation guidance for OAuth Device Flow.

Device Flow tokens are revoked from GitHub Settings → Applications → Authorized OAuth Apps, not the PAT tokens page. The current link incorrect for this flow.

-To fully revoke the token, visit: https://github.com/settings/tokens
+To fully revoke the token, go to GitHub Settings → Applications → Authorized OAuth Apps and revoke the app.
+See: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### Logout and Revoke Token
```shell
atmos auth logout -i my-github
```
To fully revoke the token, visit: https://github.com/settings/tokens
### Logout and Revoke Token
🤖 Prompt for AI Agents
In website/docs/cli/commands/auth/providers/github-user.mdx around lines 207 to
214, the guidance and link for revoking tokens points to the Personal Access
Tokens page but Device Flow tokens must be revoked via GitHub Settings →
Applications → Authorized OAuth Apps; update the text to instruct users to
revoke the token from Authorized OAuth Apps and change the link to the
Authorized OAuth Apps page
(https://github.com/settings/connections/applications) so it correctly reflects
the OAuth Device Flow revocation location.

@osterman osterman added the minor New features that do not break anything label Oct 20, 2025
@github-actions
Copy link

Warning

Changelog Entry Required

This PR is labeled minor or major but doesn't include a changelog entry.

Action needed: Add a new blog post in website/blog/ to announce this change.

Example filename: website/blog/2025-10-20-feature-name.mdx

Alternatively: If this change doesn't require a changelog entry, remove the minor or major label.

- Add GitHub User provider (github/user) following AWS SSO pattern
- Implement OAuth 2.0 Device Authorization Grant (RFC 8628)
- Remove provider-level caching - auth manager stores credentials
- Add Charm Bracelet styled UI for device flow instructions
- Add spinner during token polling with Ctrl+C support
- Add styled success message in auth login command
- Implement github/token identity for unified credential handling
- Add GitHub credential support to credential store
- Register GitHub providers and identities in factory
- Update documentation for GitHub authentication
- Update test golden snapshot for new auth subcommands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
website/docs/cli/commands/auth/providers/github-user.mdx (1)

216-223: Update token revocation guidance for OAuth Device Flow.

Device Flow tokens are managed under GitHub Settings → Applications → Authorized OAuth Apps, not the Personal Access Tokens page. The current link is incorrect for this authentication method.

Apply this diff:

-To fully revoke the token, visit: https://github.com/settings/tokens
+To fully revoke the token, go to GitHub Settings → Applications → Authorized OAuth Apps and revoke the app.
+See: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
🧹 Nitpick comments (2)
docs/prd/github-authentication-providers.md (1)

194-231: Consider adding language identifiers to fenced code blocks.

The ASCII diagrams at lines 194, 237, 276, and 308 could use language identifiers (e.g., ````text`) to satisfy markdownlint, though this is purely stylistic.

Apply this pattern to the code blocks:

-```
+```text
 ┌─────────────────────────────────────────────────────────────┐
pkg/auth/providers/github/user.go (1)

319-334: Consider extracting TTY detection for reusability (optional).

The TTY detection logic here is correct but could be extracted to a shared utility function if other providers or commands need similar functionality in the future.

Example extraction:

// In pkg/utils or pkg/ui/terminal package:
func HasTTY(f *os.File) bool {
    fileInfo, err := f.Stat()
    return err == nil && (fileInfo.Mode()&os.ModeCharDevice) != 0
}

Then use:

hasTTY := utils.HasTTY(os.Stderr)
if !hasTTY {
    fmt.Fprintln(os.Stderr, "Waiting for authentication... (Press Ctrl+C to cancel)")
} else {
    // Run spinner...
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1f13156 and cd7cc6c.

📒 Files selected for processing (16)
  • IMPLEMENTATION_COMPLETE.md (1 hunks)
  • cmd/auth_login.go (2 hunks)
  • docs/prd/github-authentication-providers.md (1 hunks)
  • go.mod (2 hunks)
  • pkg/auth/credentials/store.go (2 hunks)
  • pkg/auth/factory/factory.go (5 hunks)
  • pkg/auth/identities/github/token.go (1 hunks)
  • pkg/auth/providers/github/constants.go (1 hunks)
  • pkg/auth/providers/github/device_flow_client.go (1 hunks)
  • pkg/auth/providers/github/mock_device_flow_client_test.go (1 hunks)
  • pkg/auth/providers/github/user.go (1 hunks)
  • pkg/auth/providers/github/user_test.go (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden (1 hunks)
  • website/docs/cli/commands/auth/providers/github-app.mdx (1 hunks)
  • website/docs/cli/commands/auth/providers/github-user.mdx (1 hunks)
  • website/docs/cli/commands/auth/usage.mdx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/auth/providers/github/device_flow_client.go
  • pkg/auth/providers/github/mock_device_flow_client_test.go
  • pkg/auth/providers/github/user_test.go
🧰 Additional context used
📓 Path-based instructions (10)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Target minimum 80% coverage on new/changed lines; exclude mock files from coverage: **/mock_.go, mock_.go, **/mock/*.go.

Files:

  • docs/prd/github-authentication-providers.md
  • tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden
  • cmd/auth_login.go
  • website/docs/cli/commands/auth/usage.mdx
  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • website/docs/cli/commands/auth/providers/github-user.mdx
  • go.mod
  • pkg/auth/providers/github/user.go
  • website/docs/cli/commands/auth/providers/github-app.mdx
  • IMPLEMENTATION_COMPLETE.md
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: Follow Cobra command pattern: one command per file; load examples via //go:embed and render via utils.PrintfMarkdown in RunE.
Telemetry for new commands is automatic via RootCmd.ExecuteC(); for non-standard paths use telemetry.CaptureCmd or telemetry.CaptureCmdString.

Files:

  • cmd/auth_login.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: All comments must end with periods; enforced by golangci-lint godot across all Go comments.
Organize imports into three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically within each group; keep existing aliases.
All errors must be wrapped using static errors defined in errors/errors.go; prefer errors.Join for multiple, fmt.Errorf with %w for context, and errors.Is for checks; never rely on string comparisons.
Prefer cross-platform implementations: use SDKs over external binaries; use filepath/os facilities; gate OS-specific logic with runtime.GOOS or build tags.

Files:

  • cmd/auth_login.go
  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • pkg/auth/providers/github/user.go
**/!(*_test).go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Document all exported functions, types, and methods with Go doc comments

Files:

  • cmd/auth_login.go
  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • pkg/auth/providers/github/user.go
{cmd,internal,pkg}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

{cmd,internal,pkg}/**/*.go: Add defer perf.Track() to all public functions and critical private ones, include a blank line after it, and use package-qualified names (e.g., "exec.ProcessComponent"). Use atmosConfig if available, else nil.
Always bind environment variables with viper.BindEnv; every var must have an ATMOS_ alternative and prefer ATMOS_ over external names.
Distinguish structured logging from UI output: UI prompts/errors/status to stderr; data/results to stdout; logging for system/debug only; no UI via logging.
Most text UI must go to stderr (via utils.PrintfMessageToTUI or fmt.Fprintf(os.Stderr,...)); only data/results to stdout.

Files:

  • cmd/auth_login.go
  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • pkg/auth/providers/github/user.go
{pkg,internal,cmd}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Always use mockgen for interface mocks; never write manual mocks with many stub methods.

Files:

  • cmd/auth_login.go
  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • pkg/auth/providers/github/user.go
website/**

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Always build the website (cd website && npm run build) after modifying docs, images, sidebars, or site components to catch broken links/formatting.

Files:

  • website/docs/cli/commands/auth/usage.mdx
  • website/docs/cli/commands/auth/providers/github-user.mdx
  • website/docs/cli/commands/auth/providers/github-app.mdx
website/docs/cli/commands/**/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

All new commands/flags/parameters must be documented in Docusaurus MDX under website/docs/cli/commands//.mdx using definition lists (

) for arguments and flags and the provided frontmatter/template.

Files:

  • website/docs/cli/commands/auth/usage.mdx
  • website/docs/cli/commands/auth/providers/github-user.mdx
  • website/docs/cli/commands/auth/providers/github-app.mdx
pkg/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Place business logic in pkg rather than in cmd

Files:

  • pkg/auth/identities/github/token.go
  • pkg/auth/providers/github/constants.go
  • pkg/auth/factory/factory.go
  • pkg/auth/credentials/store.go
  • pkg/auth/providers/github/user.go
go.{mod,sum}

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

go.{mod,sum}: Manage dependencies with Go modules
Keep dependencies up to date

Files:

  • go.mod
🧠 Learnings (4)
📚 Learning: 2025-09-10T17:34:52.568Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: pkg/auth/providers/github/oidc.go:96-100
Timestamp: 2025-09-10T17:34:52.568Z
Learning: The ATMOS_ environment variable binding guideline applies to Atmos configuration variables, not external service-required environment variables like GitHub Actions OIDC variables (GITHUB_ACTIONS, ACTIONS_ID_TOKEN_*) which must use their standard names.

Applied to files:

  • website/docs/cli/commands/auth/usage.mdx
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
PR: cloudposse/atmos#1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.

Applied to files:

  • go.mod
📚 Learning: 2025-10-19T22:59:32.333Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T22:59:32.333Z
Learning: Applies to **/*.go : All comments must end with periods; enforced by golangci-lint godot across all Go comments.

Applied to files:

  • pkg/auth/providers/github/user.go
📚 Learning: 2025-10-19T22:59:32.333Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T22:59:32.333Z
Learning: Applies to {cmd,internal,pkg}/**/*.go : Most text UI must go to stderr (via utils.PrintfMessageToTUI or fmt.Fprintf(os.Stderr,...)); only data/results to stdout.

Applied to files:

  • pkg/auth/providers/github/user.go
🧬 Code graph analysis (5)
cmd/auth_login.go (1)
pkg/ui/theme/colors.go (4)
  • ColorGreen (11-11)
  • ColorDarkGray (15-15)
  • ColorWhite (20-20)
  • ColorCheckmark (19-19)
pkg/auth/identities/github/token.go (8)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (2)
  • Errorf (59-61)
  • Debug (24-26)
errors/errors.go (3)
  • ErrInvalidAuthConfig (341-341)
  • ErrInvalidIdentityKind (342-342)
  • ErrAuthenticationFailed (346-346)
pkg/schema/schema.go (2)
  • Context (381-396)
  • ConfigAndStacksInfo (460-539)
pkg/auth/types/interfaces.go (1)
  • ICredentials (129-135)
pkg/auth/types/github_user_credentials.go (1)
  • GitHubUserCredentials (8-12)
pkg/auth/types/github_app_credentials.go (1)
  • GitHubAppCredentials (8-14)
pkg/auth/types/github_oidc_credentials.go (1)
  • OIDCCredentials (14-18)
pkg/auth/factory/factory.go (5)
pkg/auth/providers/github/constants.go (3)
  • KindOIDC (12-12)
  • KindUser (6-6)
  • KindApp (9-9)
pkg/auth/providers/github/oidc.go (1)
  • NewOIDCProvider (28-41)
pkg/auth/providers/github/user.go (1)
  • NewUserProvider (50-106)
pkg/auth/providers/github/app.go (1)
  • NewAppProvider (36-106)
pkg/auth/identities/github/token.go (1)
  • NewTokenIdentity (25-41)
pkg/auth/credentials/store.go (2)
pkg/auth/types/github_user_credentials.go (1)
  • GitHubUserCredentials (8-12)
pkg/auth/types/github_app_credentials.go (1)
  • GitHubAppCredentials (8-14)
pkg/auth/providers/github/user.go (7)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/logger/log.go (3)
  • Errorf (59-61)
  • Debug (24-26)
  • Info (34-36)
errors/errors.go (3)
  • ErrInvalidProviderConfig (345-345)
  • ErrInvalidProviderKind (344-344)
  • ErrAuthenticationFailed (346-346)
pkg/auth/providers/github/constants.go (2)
  • KindUser (6-6)
  • DefaultClientID (24-24)
pkg/auth/providers/github/device_flow_client.go (1)
  • NewDeviceFlowClient (37-45)
pkg/auth/types/github_user_credentials.go (1)
  • GitHubUserCredentials (8-12)
pkg/ui/theme/colors.go (4)
  • ColorBorder (23-23)
  • ColorCyan (12-12)
  • ColorGreen (11-11)
  • ColorWhite (20-20)
🪛 LanguageTool
docs/prd/github-authentication-providers.md

[grammar] ~49-~49: Please add a punctuation mark at the end of paragraph.
Context: ...endencies**: ghtkn library, OS keychain APIs #### FR-002: GitHub App Authentication...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~63-~63: Please add a punctuation mark at the end of paragraph.
Context: ...encies**: golang-jwt library, go-github library #### FR-003: Configurable Permissions ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~94-~94: Consider using a typographic opening quote here.
Context: ... (Get, Set, GetKey methods) - Support {{ atmos.Store "github-user" ... }} template function ...

(EN_QUOTES)


[style] ~114-~114: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...mands - Description: User-friendly CLI interface for GitHub authentication - **Acceptanc...

(ACRONYM_TAUTOLOGY)


[grammar] ~188-~188: Please add a punctuation mark at the end of paragraph.
Context: ...c.) - Compatible with GitHub Enterprise Server ## 3. Architecture ### 3.1 Component ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~838-~838: Consider using a typographic opening quote here.
Context: ... - FAQ ### 10.2 Blog Post Title: "Secure GitHub Authentication with Atmos:...

(EN_QUOTES)


[typographical] ~838-~838: Consider using a typographic close quote here.
Context: ...on with Atmos: User Tokens & GitHub Apps" Content: - Problem statement (toke...

(EN_QUOTES)


[grammar] ~852-~852: Please add a punctuation mark at the end of paragraph.
Context: ...ase 2 feature, manual specification for MVP 2. Multi-Installation Support: How...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~855-~855: Please add a punctuation mark at the end of paragraph.
Context: ...e providers with different installation_ids 3. Token Refresh UI: Should we sho...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~858-~858: Please add a punctuation mark at the end of paragraph.
Context: ...cision**: Yes, warn at 5 minutes before expiration 4. Keychain Fallback: What if keyc...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~861-~861: Please add a punctuation mark at the end of paragraph.
Context: ...gradation to environment variables with warning 5. Repository Glob Patterns: Imple...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~864-~864: Please add a punctuation mark at the end of paragraph.
Context: ...rt * and ** wildcards in repository patterns 6. GitHub Enterprise Support: How ...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~867-~867: Please add a punctuation mark at the end of paragraph.
Context: ... base_url parameter for custom GitHub instances ## 12. Success Criteria ### Phase 1: ...

(PUNCTUATION_PARAGRAPH_END)


[uncategorized] ~973-~973: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Clear browser cache after auth 4. Rate Limiting - Respect GitHub API limits - C...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

website/docs/cli/commands/auth/usage.mdx

[uncategorized] ~130-~130: The official name of this software platform is spelled with a capital “H”.
Context: ...### GitHub Providers - GitHub User: [github/user](/cli/commands/auth/providers/git...

(GITHUB)


[uncategorized] ~131-~131: The official name of this software platform is spelled with a capital “H”.
Context: ... personal development - GitHub App: [github/app](/cli/commands/auth/providers/gith...

(GITHUB)


[uncategorized] ~132-~132: The official name of this software platform is spelled with a capital “H”.
Context: ... automation and bots - GitHub OIDC: [github/oidc](/cli/commands/auth/providers/git...

(GITHUB)


[uncategorized] ~258-~258: The official name of this software platform is spelled with a capital “H”.
Context: ... the box with zero configuration**. See [github/user provider documentation](/cli/comm...

(GITHUB)


[uncategorized] ~277-~277: The official name of this software platform is spelled with a capital “H”.
Context: ...or bots and CI/CD with JWT signing. See [github/app provider documentation](/cli/comma...

(GITHUB)


[uncategorized] ~297-~297: The official name of this software platform is spelled with a capital “H”.
Context: ...cation in GitHub Actions workflows. See [github/oidc provider documentation](/cli/comm...

(GITHUB)

website/docs/cli/commands/auth/providers/github-user.mdx

[uncategorized] ~14-~14: The official name of this software platform is spelled with a capital “H”.
Context: ...ser Authentication :::note Purpose The github/user provider authenticates as a GitHu...

(GITHUB)


[grammar] ~274-~274: Please add a punctuation mark at the end of paragraph.
Context: ..., workflow- **Package publishing**: Addwrite:packages` ### Environment Varia...

(PUNCTUATION_PARAGRAPH_END)


[style] ~286-~286: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...//github.com/suzuki-shunsuke/ghtkn), an excellent standalone tool for GitHub token manage...

(EN_REPEATEDWORDS_EXCELLENT)


[style] ~297-~297: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...| Recommendation: Use ghtkn if you need standalone GitHub token management. Use...

(EN_REPEATEDWORDS_NEED)


[uncategorized] ~297-~297: The official name of this software platform is spelled with a capital “H”.
Context: ...lone GitHub token management. Use Atmos github/user if you're already using Atmos for...

(GITHUB)


[typographical] ~301-~301: Consider using a typographic opening quote here.
Context: ...uthentication. ## Troubleshooting ### "Token not found in keychain" The token ...

(EN_QUOTES)


[typographical] ~301-~301: Consider using a typographic close quote here.
Context: ...ooting ### "Token not found in keychain" The token has expired or been deleted....

(EN_QUOTES)


[typographical] ~309-~309: Consider using a typographic opening quote here.
Context: ... atmos auth login -i my-github ``` ### "Failed to store token in keychain" Keyc...

(EN_QUOTES)


[typographical] ~309-~309: Consider using a typographic close quote here.
Context: ... ### "Failed to store token in keychain" Keychain access may be denied. On macO...

(EN_QUOTES)


[typographical] ~318-~318: Consider using a typographic opening quote here.
Context: ...ry/Keychains/login.keychain-db ``` ### "Device code expired" You took too long ...

(EN_QUOTES)


[typographical] ~318-~318: Consider using a typographic close quote here.
Context: ...eychain-db ``` ### "Device code expired" You took too long to authorize. Device...

(EN_QUOTES)


[typographical] ~326-~326: Consider using typographic quotation marks here.
Context: ... atmos auth login -i my-github ``` ### "Insufficient scope" Your token doesn't have the required p...

(EN_QUOTES)

website/docs/cli/commands/auth/providers/github-app.mdx

[uncategorized] ~14-~14: The official name of this software platform is spelled with a capital “H”.
Context: ...App Authentication :::note Purpose The github/app provider authenticates as a GitHub...

(GITHUB)


[typographical] ~175-~175: Consider using typographic quotation marks here.
Context: ...ture docs URL - Webhook: Uncheck "Active" (not needed for CLI use) ### 2. Config...

(EN_QUOTES)


[grammar] ~263-~263: Please add a punctuation mark at the end of paragraph.
Context: ...ly - Never caches tokens beyond command execution ### Private Key Security - **Never co...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~387-~387: Consider using a typographic opening quote here.
Context: ...m-aws-rds" ``` ## Troubleshooting ### "Failed to generate JWT" Cause: Inva...

(EN_QUOTES)


[typographical] ~387-~387: Consider using a typographic close quote here.
Context: ...bleshooting ### "Failed to generate JWT" Cause: Invalid private key format ...

(EN_QUOTES)


[typographical] ~396-~396: Consider using a typographic opening quote here.
Context: ...openssl rsa -in key.pem -check ``` ### "Installation token request failed with s...

(EN_QUOTES)


[typographical] ~396-~396: Consider using a typographic close quote here.
Context: ...ion token request failed with status 404" Cause: Invalid installation_id or ...

(EN_QUOTES)


[typographical] ~405-~405: Consider using a typographic opening quote here.
Context: ...Check app has not been uninstalled ### "Failed to parse private key" Cause:...

(EN_QUOTES)


[typographical] ~405-~405: Consider using a typographic close quote here.
Context: ...talled ### "Failed to parse private key" Cause: Private key contains invali...

(EN_QUOTES)


[typographical] ~411-~411: Consider using typographic quotation marks here.
Context: ...private key in GitHub app settings ### "Insufficient permissions" Cause: App doesn't have required p...

(EN_QUOTES)

IMPLEMENTATION_COMPLETE.md

[uncategorized] ~8-~8: The official name of this software platform is spelled with a capital “H”.
Context: ...Providers - ✅ GitHub User Provider (pkg/auth/providers/github/user.go) - OAuth Device Flow with **ze...

(GITHUB)


[uncategorized] ~9-~9: The official name of this software platform is spelled with a capital “H”.
Context: ...Auth App** - ✅ GitHub App Provider (pkg/auth/providers/github/app.go) - JWT + Installation Tokens - ...

(GITHUB)


[uncategorized] ~10-~10: The official name of this software platform is spelled with a capital “H”.
Context: ...on Tokens - ✅ GitHub OIDC Provider (pkg/auth/providers/github/oidc.go) - Already existed, updated - ...

(GITHUB)


[uncategorized] ~11-~11: The official name of this software platform is spelled with a capital “H”.
Context: ...ed, updated - ✅ Device Flow Client (pkg/auth/providers/github/device_flow_client.go) - Real implemen...

(GITHUB)


[uncategorized] ~12-~12: The official name of this software platform is spelled with a capital “H”.
Context: ...plementation - ✅ OS Keychain Store (pkg/auth/providers/github/keychain_store.go) - Cross-platform - ...

(GITHUB)


[uncategorized] ~13-~13: The official name of this software platform is spelled with a capital “H”.
Context: ...ss-platform - ✅ Provider Constants (pkg/auth/providers/github/constants.go) - KindUser, KindApp, Kin...

(GITHUB)


[uncategorized] ~16-~16: The official name of this software platform is spelled with a capital “H”.
Context: ...ls Types - ✅ GitHubUserCredentials (pkg/auth/types/github_user_credentials.go) - ✅ **GitHubAppCr...

(GITHUB)


[uncategorized] ~17-~17: The official name of this software platform is spelled with a capital “H”.
Context: ...ials.go) - ✅ **GitHubAppCredentials** (pkg/auth/types/github_app_credentials.go`) #### Commands - ✅...

(GITHUB)


[uncategorized] ~24-~24: The official name of this software platform is spelled with a capital “H”.
Context: ...(pkg/auth/factory/factory.go) - Added github/user and github/app - ✅ **Provider Cons...

(GITHUB)


[uncategorized] ~24-~24: The official name of this software platform is spelled with a capital “H”.
Context: ...ry/factory.go`) - Added github/user and github/app - ✅ Provider Constants - Used t...

(GITHUB)


[uncategorized] ~85-~85: The official name of this software platform is spelled with a capital “H”.
Context: ... ### ❌ NOT Implemented (Correctly) - ❌ pkg/store/github_user_store.go - WRONG ARCHITECTURE...

(GITHUB)


[uncategorized] ~86-~86: The official name of this software platform is spelled with a capital “H”.
Context: ..._store.go- **WRONG ARCHITECTURE** - ❌pkg/store/github_app_store.go` - WRONG ARCHITECTURE ...

(GITHUB)


[typographical] ~88-~88: Consider using a typographic opening quote here.
Context: ... - NOT NEEDED - ❌ Template function {{ atmos.Store "github-user" }} - NOT NEEDED ### ✅...

(EN_QUOTES)


[grammar] ~88-~88: Please add a punctuation mark at the end of paragraph.
Context: ...{ atmos.Store "github-user" }}` - NOT NEEDED ### ✅ Correct Architecture GitHub au...

(PUNCTUATION_PARAGRAPH_END)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/github-authentication-providers.md

194-194: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


237-237: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


276-276: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


308-308: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (macos)
  • GitHub Check: Run pre-commit hooks
  • GitHub Check: website-deploy-preview
  • GitHub Check: Analyze (go)
  • GitHub Check: Lint (golangci)
  • GitHub Check: autofix
  • GitHub Check: Summary
🔇 Additional comments (19)
tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden (1)

8-14: Snapshot correctly updated for new auth subcommands.

The updated subcommand list accurately reflects the addition of git-credential and logout to the atmos auth command tree. Alphabetical ordering is maintained, and formatting is consistent.

go.mod (2)

3-3: Toolchain update looks good.

The Go toolchain bump to 1.25.1 is appropriate for this feature addition.


45-45: JWT dependency correctly promoted to direct.

This aligns with the GitHub App provider implementation that signs JWTs for installation tokens.

pkg/auth/credentials/store.go (2)

55-60: Store implementation for GitHub credentials looks good.

The new credential types follow the established pattern for AWS and OIDC credentials. Type strings match between Store and Retrieve methods.


105-116: Retrieve implementation for GitHub credentials is consistent.

Error handling and unmarshaling follow the same pattern as existing credential types.

IMPLEMENTATION_COMPLETE.md (1)

1-175: Implementation tracking document is comprehensive.

This provides a clear summary of what was completed and what remains optional. Nice work documenting the 80.8% test coverage achievement.

pkg/auth/identities/github/token.go (3)

24-41: Constructor implementation follows guidelines.

Uses defer perf.Track(), validates config, and provides clear error messages with wrapped errors.


59-84: Authenticate method handles multiple credential types correctly.

The type switch properly handles GitHubUserCredentials, GitHubAppCredentials, and OIDCCredentials with appropriate logging for each path.


107-112: PostAuthenticate no-op is appropriate.

The comment clearly explains that environment variables are handled elsewhere by the auth manager, so this no-op is intentional.

pkg/auth/factory/factory.go (2)

28-33: Provider factory correctly uses constants.

The refactoring from hardcoded "github/oidc" to githubProviders.KindOIDC and addition of KindUser and KindApp improves maintainability and reduces typo risk.


53-54: GitHub token identity properly registered.

The new "github/token" identity kind is correctly wired to the NewTokenIdentity constructor.

cmd/auth_login.go (1)

55-101: Styled authentication output enhances user experience.

The lipgloss-based UI provides clear visual feedback while maintaining proper output to stderr per coding guidelines. Conditional field rendering handles varying authentication result types appropriately.

pkg/auth/providers/github/constants.go (2)

4-13: Provider kind constants improve maintainability.

Centralizing these constants prevents typos and makes refactoring easier across the codebase.


15-24: DefaultClientID documentation is excellent.

The comment clearly explains the source (GitHub CLI), why it's safe to embed, and how users can override it. This level of documentation is helpful for future maintainers.

website/docs/cli/commands/auth/providers/github-app.mdx (1)

1-450: Excellent documentation page for GitHub App authentication.

The documentation is comprehensive, well-structured, and covers all essential aspects: authentication flow, configuration, permissions, usage examples, security considerations, and troubleshooting. The Mermaid diagrams effectively illustrate the JWT-based flow, and the examples are practical and correct.

website/docs/cli/commands/auth/usage.mdx (2)

125-132: Well-organized provider categorization.

The addition of "AWS Providers" and "GitHub Providers" subsections improves documentation navigation and clearly separates authentication methods by cloud provider.


252-313: Comprehensive GitHub authentication section with clear examples.

The new section effectively consolidates GitHub authentication methods (User, App, OIDC) with practical configuration examples and links to detailed provider documentation. The examples are correct and align with the provider implementations.

website/docs/cli/commands/auth/providers/github-user.mdx (1)

1-215: Comprehensive documentation for GitHub User authentication.

The documentation effectively covers OAuth Device Flow authentication with excellent structure, practical examples, and clear security guidance. The zero-config setup using the default GitHub CLI OAuth app is particularly well-explained, making it easy for users to get started.

Also applies to: 224-400

pkg/auth/providers/github/user.go (1)

1-362: Solid implementation of GitHub User authentication via OAuth Device Flow.

The provider correctly implements Device Flow authentication with proper error handling, UI output to stderr, perf tracking, and cross-platform TTY detection. All coding guidelines are followed: comments end with periods, errors use static types from errUtils, and UI interactions go to stderr.

- Extract helper functions to reduce cyclomatic and cognitive complexity
  - loadPrivateKey: Split into loadPrivateKeyPEM and parseRSAPrivateKey
  - NewUserProvider: Extract config parsing into helper functions
  - pollOnce: Extract response processing and logging
  - Spinner functions: Extract TTY handling into spinnerUI type

- Fix function length issues (max 60 lines)
  - pollOnce: Reduced from 71 to 33 lines by extracting helpers
  - runSpinnerDuringPoll: Reduced from 62 to 30 lines with spinnerUI
  - runSpinnerDuringWebFlow: Reduced from 62 to 30 lines with spinnerUI

- Fix revive function-result-limit
  - pollOnce: Wrap 4 return values into pollResult struct

- Add static error sentinels in errors/errors.go
  - ErrPrivateKeyEnvNotSet
  - ErrPrivateKeyConfigMissing
  - ErrPEMDecodeFailed
  - ErrPrivateKeyNotRSA
  - ErrInstallationTokenRequest

- Replace magic numbers with named constants
  - loginBoxWidth = 60 for display box width
  - loginLabelWidth = 12 for label width
  - httpClientTimeout = 30 for GitHub API timeout
  - deviceFlowHTTPTimeout = 30 for device flow timeout
  - logKeyIdentity = "identity" for logging

- Add justified nolint directives
  - auth_git_credential.go: error=nil intentional per git protocol
  - auth_logout.go: authManager unused until TODO implemented
  - app.go: os.Getenv expected pattern for GitHub App keys

- Fix comment capitalization for godot linter
  - All constant comments now start without lowercase variable names

All linting issues resolved - make lint passes with 0 issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@osterman osterman requested a review from a team as a code owner October 21, 2025 00:26
@mergify
Copy link

mergify bot commented Oct 21, 2025

Important

Cloud Posse Engineering Team Review Required

This pull request modifies files that require Cloud Posse's review. Please be patient, and a core maintainer will review your changes.

To expedite this process, reach out to us on Slack in the #pr-reviews channel.

@mergify mergify bot added the needs-cloudposse Needs Cloud Posse assistance label Oct 21, 2025

// Output credentials in git credential helper format.
fmt.Printf("username=x-access-token\n")
fmt.Printf("password=%s\n", token)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

Sensitive data returned by an access to passwdParts
flows to a logging call.

Copilot Autofix

AI 5 months ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

@mergify
Copy link

mergify bot commented Oct 21, 2025

💥 This pull request now has conflicts. Could you fix it @osterman? 🙏

@mergify mergify bot added the conflict This PR has conflicts label Oct 21, 2025
osterman added a commit that referenced this pull request Dec 23, 2025
Added PR links to milestones across all initiatives:

Auth Initiative:
- EKS Kubeconfig → PR #1884
- ECR Authentication → PR #1859
- GitHub Apps → PR #1683

Developer Experience:
- Streaming Terraform UI → PR #1908
- Native CI integration → PR #1891

Workflows:
- Unified task execution → PR #1901
- New workflow step types → PR #1899

Extensibility:
- Added !unset YAML function → PR #1521
- Added !append YAML function → PR #1513

Vendoring:
- Vendor registry pattern → PR #1889
- Just-in-time vendoring → PR #1877
- Component workdir provisioning → PR #1876

Terragrunt Parity:
- Multi-stack formats → PR #1842

CI/CD:
- CI Summary Templates → PR #1891
- Terraform command registry → PR #1891
aknysh added a commit that referenced this pull request Dec 26, 2025
* feat: Add comprehensive roadmap page with initiatives and milestones

- Add Roadmap component with interactive initiative cards
- Create MilestoneList, MilestoneDrawer, and ProgressBar components
- Add Tooltip component for PR/issue titles with theme-aware styling
- Implement responsive design with flexbox alignment fixes
- Add extensive roadmap data with documented milestones across 10 initiatives
- Add changelog and docs links to all relevant milestones
- Update Docusaurus navbar with Roadmap link

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* fix: Address CodeRabbit review comments for roadmap components

- Fix type mismatch: use undefined instead of null for selectedMilestone
- Make changelogSlugs optional in Initiative interface
- Replace fragile status className construction with explicit mapping
- Reduce tooltip z-index from 9999 to 1002 (just above drawer)
- Add scroll/resize listeners for tooltip position updates
- Improve keyboard accessibility with tabIndex, aria-describedby, role="tooltip"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Update Customizable list output description

Focus on custom column views rather than output formats.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: Move Component-aware tab completion to DX initiative

Tab completion is more about developer experience than discoverability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(roadmap): rename 'Customizable list output' to 'Customizable list columns'

Clarifies that this is an improvement to existing list commands (added Q1 2025),
not a new feature. The Q4 2025 milestone added customizable column support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(roadmap): update initiative names and add new milestones

- Rename 'Migration & Code Generation' to 'Feature Parity with Terragrunt'
- Rename 'Quality & Community' to 'Code Quality and Community'
- Change 'Learning section' to 'New learning section'
- Add Native Terraform to migration guides list
- Add Roadmap milestone to Documentation initiative

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): correct design patterns docs link

Changed /design-patterns/design-patterns to /design-patterns

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add 'Request a Feature' link to initiatives section

Adds a prominent link to GitHub feature request issue template
for users who want to suggest new features for the roadmap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add 'View Features' link to GitHub issues

Adds a link to browse existing feature requests and issues
alongside the 'Request a Feature' link.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): rename 'View Features' to 'View Issues'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(roadmap): reorganize Feature Parity with Terragrunt initiative

Changes to Feature Parity with Terragrunt:
- Keep: File-scoped locals
- Rename: Stack name field → Imperative stack names
- Rename: Generate section inheritance → File generation (generate blocks)
- Rename: Backend provisioning → Automatic backend provisioning
- Add: AWS context YAML functions (!aws.account-id, !aws.region, etc.)
- Remove: Metadata inheritance (merged into other features)

Moved to Extensibility & Custom Components:
- !literal YAML function
- metadata.name for component workspace keys

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add planned Terragrunt parity features

- Automatic source provisioning (no vendoring required)
- Concurrent component provisioning
- plan --all and apply --all commands
- Automatic provider caching

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): update DX milestones

- Update parent directory search description to emphasize running from any directory
- Add filesystem paths for components feature

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): use neutral blue gradient for progress bars

Replace orange/red colors with lighter blues to avoid
'behind schedule' connotation - progress just means 'not
as far along yet', not delayed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(roadmap): reorganize quality and docs initiatives

- Rename 'Code Quality and Community' to 'Code Quality and Test Coverage'
- Rename 'Documentation Overhaul' to 'Documentation Overhaul and Community Announcements'
- Move 'Changelog introduction' from quality to docs initiative
- Rename migration guides milestone to 'Added migration guides'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add nightly releases and PR feature releases to quality initiative

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add 'Push for stability' to quality initiative

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): clarify backend provisioning vs backend generation

Backend provisioning is about provisioning the backend itself (S3 bucket,
DynamoDB table) for cold-start scenarios, not just generating backend.tf files.

* fix(roadmap): remove DynamoDB from backend provisioning description

DynamoDB locking is no longer needed for S3 state backends.

* fix(roadmap): mention native S3 state locking for backend provisioning

* feat(roadmap): mark --all flags as shipped, add PR links for planned features

- Mark 'plan --all' and 'apply --all' as shipped (Q4 2025)
- Add PR #1877 link for automatic source provisioning
- Add PR #1882 link for automatic provider caching

* feat(roadmap): add comprehensive PR links to milestones

Added PR links to milestones across all initiatives:

Auth Initiative:
- EKS Kubeconfig → PR #1884
- ECR Authentication → PR #1859
- GitHub Apps → PR #1683

Developer Experience:
- Streaming Terraform UI → PR #1908
- Native CI integration → PR #1891

Workflows:
- Unified task execution → PR #1901
- New workflow step types → PR #1899

Extensibility:
- Added !unset YAML function → PR #1521
- Added !append YAML function → PR #1513

Vendoring:
- Vendor registry pattern → PR #1889
- Just-in-time vendoring → PR #1877
- Component workdir provisioning → PR #1876

Terragrunt Parity:
- Multi-stack formats → PR #1842

CI/CD:
- CI Summary Templates → PR #1891
- Terraform command registry → PR #1891

* feat(roadmap): improve milestone labels with descriptive context

Update milestone labels to describe what each feature does rather than
just listing the command or feature name:

- Discoverability: Change "Added `atmos list stacks`" to
  "`atmos list stacks` to browse all configured stacks" etc.
- Auth: Change "EKS Kubeconfig integration" to "Automatic EKS kubeconfig
  tied to identities" and similar for ECR

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add Featured Improvements section with 6 key highlights

Add a prominent Featured Improvements section near the top of the roadmap
page showcasing major capabilities:

1. Dev Container Support - Consistent development environments
2. Toolchain Management - Automatic tool installation and versioning
3. Cloud Authentication - Unified identity layer across clouds
4. Beautiful Workflows - Multi-step automation with typed inputs
5. Source Provisioning - Just-in-time component fetching (in-progress)
6. Native CI/CD Support - Local = CI experience (in-progress)

Also fixes:
- Provider auto-generation marked as shipped (Q3 2025)
- Devcontainer docs link corrected

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): enhance featured section and milestone grouping

- Add PRD links to featured items (devcontainer, keyring-backends, provisioner-system, terraform-registry-migration)
- Fix statuses: Toolchain Management and Beautiful Workflows changed from shipped to in-progress
- Update quarters: Native CI/CD, Toolchain, Workflows, and Source Provisioning set to Q1 2026
- Add sorting by status (shipped first) and quarter (earlier first)
- Implement milestone grouping with categories (Featured Improvements, Everything Else) and priorities (high, nice-to-have)
- Add PR links for Toolchain Management (#1686) and Beautiful Workflows (#1899)
- Update Cloud Authentication description with "Zero local config required"
- Rename "Initiatives" section to "Major Initiatives"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(roadmap): add benefits field, clickable featured cards, and overall progress stats

- Add benefits field to all 89 milestones explaining "Why It Matters"
- Add benefits to 6 featured items with benefit-focused explanations
- Create FeaturedDrawer component for featured card detail view
- Make featured cards clickable with drawer showing description/benefits
- Create RoadmapStats component showing overall progress (shipped/in-progress/planned)
- Add animated progress bar with color-coded segments
- Expand changelog-check.yml to also require roadmap.js updates for minor/major PRs
- Update CLAUDE.md with roadmap update requirements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): simplify drawer links to reduce visual noise

Remove heavy background colors from drawer link buttons and convert
them to simple inline text links that wrap horizontally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): use plain colors for drawer links, one per line

- Change links to use neutral emphasis colors instead of brand colors
- Display each link on its own line for cleaner vertical layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style(roadmap): use brightening instead of underline for drawer link hover

Change drawer link hover behavior to brighten text color instead of
adding underline for cleaner visual feedback.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(roadmap): add CI/local parity to cloud auth benefits

Highlight that cloud authentication works identically in CI and
locally, a key differentiator for the unified auth system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style(roadmap): increase gap between progress bar and Major Initiatives

Add more breathing room between the Overall Progress section and
the Major Initiatives heading below it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style(roadmap): double gap between progress bar and Major Initiatives

Increase bottom margin from 3rem to 6rem for more visual separation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(roadmap): mark Terragrunt parity milestones as featured

Mark all major Terragrunt feature parity milestones as featured:
- File-scoped locals
- Imperative stack names
- File generation (generate blocks)
- Automatic backend provisioning
- AWS context YAML functions
- Multi-stack formats (YAML, JSON and HCL)
- Automatic provider caching
- Automatic source provisioning
- Provider auto-generation
- Concurrent component provisioning

Also link PR #1876 (workdir provisioning) to concurrent component
provisioning milestone.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): address CodeRabbit review feedback

- Add target="_blank" and rel="noopener noreferrer" to external GitHub
  links in FeaturedSection.tsx (PRD and PR links)
- Add target="_blank" and rel="noopener noreferrer" to external GitHub
  links in InitiativeCard.tsx (issues and PRs)
- Add target="_blank" and rel="noopener noreferrer" to external GitHub
  links in FeaturedDrawer.tsx (PRD and PR links)
- Guard against division by zero in RoadmapStats.tsx progress bar
  width calculations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(blog): introduce the Atmos product roadmap

Add a blog post announcing the new public product roadmap page, highlighting:
- Featured improvements like Dev Containers, Cloud Auth, and Workflows
- Major initiatives including Terragrunt parity and documentation overhaul
- Overall progress tracking across all milestones
- How to get involved and provide feedback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs(roadmap): reconcile changelog announcements with roadmap

Add missing changelog links to existing milestones:
- workflow-file-auto-discovery
- automatic-backend-provisioning
- path-based-component-resolution
- aws-yaml-functions
- product-roadmap

Add new milestones for shipped features:
- Auth: auth shell, SSO auto-provisioning, identity flag for describe
- DX: terminal themes, helpful errors, provenance tracking, global env,
  metadata inheritance, interactive terraform prompts
- Extensibility: !random, !env stack manifest support, circular
  dependency detection, deferred evaluation, boolean flags

Update progress percentages:
- Auth: 80% → 85%
- DX: 75% → 90%
- Extensibility: 50% → 80%

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(roadmap): correct broken documentation links

Update doc links to use correct paths:
- /cli/configuration/configuration → /cli/configuration
- /cli/commands/commands → /cli/commands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* address comments and feedback

* address comments and feedback

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
Co-authored-by: aknysh <andriy.knysh@gmail.com>
@mergify mergify bot removed the conflict This PR has conflicts label Jan 18, 2026
@mergify
Copy link

mergify bot commented Jan 18, 2026

💥 This pull request now has conflicts. Could you fix it @osterman? 🙏

@mergify mergify bot added the conflict This PR has conflicts label Jan 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflict This PR has conflicts minor New features that do not break anything needs-cloudposse Needs Cloud Posse assistance size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant