Skip to content

fix(hooks): resolve $ATMOS_COMPONENT_PATH via metadata.component for non-JIT components - #2805

Closed
Andriy Knysh (aknysh) wants to merge 3 commits into
mainfrom
aknysh/hooks-component-path-metadata-component
Closed

Andriy Knysh (aknysh) wants to merge 3 commits into
mainfrom
aknysh/hooks-component-path-metadata-component

Conversation

@aknysh

@aknysh Andriy Knysh (aknysh) commented Jul 25, 2026 •

Copy link
Copy Markdown
Member

what

  • Fixed $ATMOS_COMPONENT_PATH resolution in lifecycle hooks for plain (non-JIT) components that point at a different local component folder via metadata.component.
  • GetHooks now backfills the resolved Terraform component (FinalComponent, and ComponentFolderPrefix for subpath values like shared/nat-gateway) onto the hook context from the ExecuteDescribeComponent output it already fetches — no extra describe call.
  • Added a regression test reproducing the exact scenario from the issue (an alias component with no folder of its own plus an infracost hook) and a table-driven unit test for the backfill logic.
  • Added a fix record at docs/fixes/2026-07-25-hooks-component-path-metadata-component.md.

why

references

Summary by CodeRabbit

  • Bug Fixes
    • Fixed hook path resolution for components using metadata.component.
    • Hooks now use the resolved metadata component directory (not the stack-facing alias path).
    • Improved preservation and population of component folder prefix details during hook execution setup.
  • Tests
    • Added unit coverage for enrichment behavior, including missing/non-string component values and existing info preservation.
    • Added integration-style coverage to ensure correct metadata resolution for hook path computation.
  • Documentation
    • Added release documentation explaining the hook path resolution fix and verification steps.

…non-JIT components

For a component aliasing another local component folder via metadata.component,
hook kinds consuming $ATMOS_COMPONENT_PATH (infracost, trivy, checkov, kics,
tflint, command) resolved the path from the raw stack-facing component name and
scanned a directory that does not exist. GetHooks now backfills the resolved
Terraform component from the describe output it already fetches, so
componentPathFor's non-workdir fallback joins the metadata.component target.

Fixes #2799

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aknysh
Andriy Knysh (aknysh) requested a review from a team as a code owner July 25, 2026 15:58
@atmos-pro

atmos-pro Bot commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More. Ask AI.

@aknysh Andriy Knysh (aknysh) added the patch A minor, backward compatible change label Jul 25, 2026
@aknysh Andriy Knysh (aknysh) self-assigned this Jul 25, 2026
@github-actions github-actions Bot added the size/m Medium size PR label Jul 25, 2026
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7fa3613d-e634-4f13-9e43-a95bfe0ca2f1

📥 Commits

Reviewing files that changed from the base of the PR and between 8089c17 and 929a8cd.

📒 Files selected for processing (1)
  • docs/fixes/2026-07-25-hooks-component-path-metadata-component.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/fixes/2026-07-25-hooks-component-path-metadata-component.md

📝 Walkthrough

Walkthrough

Changes

Hook path enrichment

Layer / File(s) Summary
Describe metadata enrichment
pkg/hooks/hooks.go, docs/fixes/...
GetHooks enriches hook metadata from component describe output, deriving FinalComponent and ComponentFolderPrefix without overwriting existing values.
Enrichment and alias-path validation
pkg/hooks/hooks_test.go, docs/fixes/...
Tests cover component parsing, invalid inputs, overwrite guards, and hook paths resolved from metadata.component aliases.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GetHooks
  participant ExecuteDescribeComponent
  participant enrichInfoFromDescribe
  participant componentPathFor
  GetHooks->>ExecuteDescribeComponent: Describe component
  ExecuteDescribeComponent-->>GetHooks: Resolved component sections
  GetHooks->>enrichInfoFromDescribe: Enrich execution info
  enrichInfoFromDescribe-->>GetHooks: Component path metadata
  GetHooks->>componentPathFor: Resolve hook scan path
  componentPathFor-->>GetHooks: Metadata component directory
Loading

Possibly related issues

Possibly related PRs

  • cloudposse/atmos#2802 — Addresses the same component metadata and hook path resolution flow through a different enrichment location.
  • cloudposse/atmos#2736 — Shares the GetHooks code path for bulk per-component hook execution and hook path resolution.

Suggested reviewers: osterman

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: hook path resolution now uses metadata.component for non-JIT components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aknysh/hooks-component-path-metadata-component

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.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 25, 2026
@github-actions

Copy link
Copy Markdown

Resource Changes Found for bucket in test

Atmos CI

create

Plan: 4 to add, 0 to change, 0 to destroy.
To reproduce this locally, run:

atmos terraform plan bucket -s test

Create

+ aws_s3_bucket.checkov_target
+ aws_s3_bucket.this
+ aws_s3_bucket.trivy_target
+ aws_s3_bucket_public_access_block.trivy_target
Terraform Plan Summary
  # aws_s3_bucket.checkov_target will be created
  + resource "aws_s3_bucket" "checkov_target" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-checkov-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = (known after apply)
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket.this will be created
  + resource "aws_s3_bucket" "this" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags                        = {
          + "AtmosFixture" = "native-ci-e2e"
          + "Stage"        = "test"
        }
      + tags_all                    = {
          + "AtmosFixture" = "native-ci-e2e"
          + "Stage"        = "test"
        }
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket.trivy_target will be created
  + resource "aws_s3_bucket" "trivy_target" {
      + acceleration_status         = (known after apply)
      + acl                         = (known after apply)
      + arn                         = (known after apply)
      + bucket                      = "atmos-native-ci-e2e-trivy-test"
      + bucket_domain_name          = (known after apply)
      + bucket_prefix               = (known after apply)
      + bucket_regional_domain_name = (known after apply)
      + force_destroy               = false
      + hosted_zone_id              = (known after apply)
      + id                          = (known after apply)
      + object_lock_enabled         = (known after apply)
      + policy                      = (known after apply)
      + region                      = (known after apply)
      + request_payer               = (known after apply)
      + tags_all                    = (known after apply)
      + website_domain              = (known after apply)
      + website_endpoint            = (known after apply)

      + cors_rule (known after apply)

      + grant (known after apply)

      + lifecycle_rule (known after apply)

      + logging (known after apply)

      + object_lock_configuration (known after apply)

      + replication_configuration (known after apply)

      + server_side_encryption_configuration (known after apply)

      + versioning (known after apply)

      + website (known after apply)
    }

  # aws_s3_bucket_public_access_block.trivy_target will be created
  + resource "aws_s3_bucket_public_access_block" "trivy_target" {
      + block_public_acls       = true
      + block_public_policy     = true
      + bucket                  = (known after apply)
      + id                      = (known after apply)
      + ignore_public_acls      = true
      + restrict_public_buckets = true
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + bucket_name = "atmos-native-ci-e2e-test"

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 25, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.80%. Comparing base (1b965ac) to head (c41e94d).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #2805   +/-   ##
=======================================
  Coverage   81.80%   81.80%           
=======================================
  Files        1793     1793           
  Lines      173037   173048   +11     
=======================================
+ Hits       141545   141567   +22     
+ Misses      23686    23675   -11     
  Partials     7806     7806           
Flag Coverage Δ
unittests 81.80% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
pkg/hooks/hooks.go 83.16% <100.00%> (+0.39%) ⬆️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aknysh

Copy link
Copy Markdown
Member Author

Closing in favor of #2802, which fully subsumes this fix: it resolves metadata.component via a full ProcessStacks pass in prepareHookContext (covering FinalComponent/ComponentFolderPrefix the same way this PR's GetHooks backfill did), and additionally fixes JIT source provisioning ordering before hooks, runs hook subprocesses from the resolved component directory, and extends path resolution to all provisionable component types. Both PRs close #2799.

@atmos-pro

atmos-pro Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Note

Atmos Pro  

Waiting for your GitHub Actions workflow to upload affected stacks.
Learn More.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hooks: built-in kinds resolve $ATMOS_COMPONENT_PATH to the wrong directory for non-JIT components using metadata.component

1 participant