Skip to content

Add S3/ECR "down" command resource handling#772

Merged
chrisaddy merged 2 commits intomasterfrom
infrastructure-down-command-fixes
Feb 25, 2026
Merged

Add S3/ECR "down" command resource handling#772
chrisaddy merged 2 commits intomasterfrom
infrastructure-down-command-fixes

Conversation

@forstmeier
Copy link
Copy Markdown
Collaborator

@forstmeier forstmeier commented Feb 25, 2026

Overview

Changes

  • add imports for S3/ECR resources
  • suppress code recommendations from ECR resources
  • add "suffix" for bucket names to Pulumi secrets

Context

Another bit of cleanup for stuff I encountered running the infrastructure.

Summary by CodeRabbit

  • Chores
    • Added automatic per-deployment random suffixes for resource names to avoid collisions.
    • Made infrastructure imports idempotent and added steps to reliably import storage resources.
    • Strengthened teardown behavior by retaining critical storage resources and adjusting container registry cleanup.
    • Minor CI/docs tweak: expanded markdown lint exclusions.

@forstmeier forstmeier self-assigned this Feb 25, 2026
@forstmeier forstmeier added python Python code updates markdown Markdown code updates labels Feb 25, 2026
@github-project-automation github-project-automation Bot moved this to In Progress in Overview Feb 25, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

Adds a secret-backed random suffix to Pulumi production config and wires it into infrastructure code to produce unique S3 bucket names; updates import scripts and resource options (retain_on_delete / force_delete) for S3 and ECR resources.

Changes

Cohort / File(s) Summary
Pulumi production config
infrastructure/Pulumi.production.yaml
Added fund:randomSuffix secure configuration entry.
Pulumi program
infrastructure/__main__.py
Read randomSuffix from stack secret; construct bucket names by concatenating prefix + suffix; set retain_on_delete=True for S3-related resources; set force_delete=True for multiple ECR repositories; export unsecreted bucket names.
Automation / imports & docs
maskfile.md
Generate/store random suffix in config if missing; add idempotent Pulumi import flags (--generate-code=false) and new import commands for data/model S3 buckets and related resources; extend markdown lint exclusions.

Sequence Diagram(s)

sequenceDiagram
  participant DevEnv as Dev/Script
  participant Pulumi as Pulumi Program
  participant Config as Pulumi Stack Config (secret)
  participant AWS as AWS Resources (S3, ECR)

  DevEnv->>Config: ensure `fund:randomSuffix` exists (generate if missing)
  Pulumi->>Config: read `randomSuffix` (secret)
  Pulumi->>Pulumi: concat(prefix, randomSuffix) -> bucket names
  Pulumi->>AWS: create S3 buckets, encryption, public access, versioning (retain_on_delete)
  Pulumi->>AWS: create ECR repositories (force_delete=True)
  AWS-->>Pulumi: resource ARNs/names
  Pulumi->>DevEnv: export bucket names (unsecret)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: adding resource handling for S3 and ECR resources during infrastructure teardown, which is reflected in the additions of retain_on_delete and force_delete options.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch infrastructure-down-command-fixes

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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 25, 2026

Greptile Summary

This PR improves infrastructure resource management by enabling proper teardown of S3 buckets and ECR repositories. The changes implement deterministic S3 bucket naming using a random suffix stored in Pulumi secrets, add retain_on_delete=True to all S3 bucket child resources to prevent orphaned resources, enable force_delete=True on ECR repositories to allow deletion during teardown, and update the infrastructure up command to automatically import existing S3 resources. The bucket name exports are properly wrapped in pulumi.Output.unsecret() to avoid marking downstream consumers as secret.

Key improvements:

  • S3 buckets now use deterministic names instead of prefixes for reliable import/export
  • S3 bucket child resources inherit retention policy to prevent orphaned configurations
  • ECR repositories can be deleted during teardown (with note about potential switch to retention)
  • Infrastructure up command handles existing S3 resources via import

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes are well-designed improvements to infrastructure resource lifecycle management. The use of retain_on_delete=True for S3 resources prevents accidental data loss, while force_delete=True on ECR repositories is appropriately documented with guidance on when to switch to retention. The random suffix approach ensures bucket name uniqueness and enables reliable resource imports. The pulumi.Output.unsecret() wrapping prevents unintended secret propagation. All changes follow infrastructure-as-code best practices and align with the cleanup goals described in the PR.
  • No files require special attention

Important Files Changed

Filename Overview
infrastructure/Pulumi.production.yaml Added randomSuffix configuration for unique S3 bucket naming across deployments
infrastructure/main.py Replaced bucket prefixes with deterministic names using suffix, added retain_on_delete to S3 resources, added force_delete to ECR repositories, and wrapped bucket exports in unsecret()
maskfile.md Added random suffix generation/retrieval, added S3 resource imports with suffix interpolation, added --generate-code=false flag to imports, and excluded .scratchpad from markdown linting

Last reviewed commit: 5cbb2f7

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances infrastructure lifecycle management by enabling proper handling of S3 buckets and ECR repositories during stack teardown and recreation. The changes introduce a deterministic naming scheme for S3 buckets using a randomly generated suffix stored in Pulumi secrets, add resource import statements for S3 resources, configure ECR repositories for automatic deletion on teardown, and suppress code generation during imports.

Changes:

  • Added random suffix generation and storage for deterministic S3 bucket naming across infrastructure up/down cycles
  • Added S3 resource import statements (bucket, encryption, versioning, public access blocks) to maskfile
  • Added force_delete=True to all ECR repositories and retain_on_delete=True to S3 bucket sub-resources
  • Added --generate-code=false flag to all pulumi import commands to suppress code generation recommendations
  • Added .scratchpad to markdown linter ignore list

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
maskfile.md Adds random suffix generation, S3 resource imports with --generate-code=false flag, and .scratchpad to markdown lint ignore list
infrastructure/main.py Changes S3 buckets from bucket_prefix to explicit bucket names with random suffix, adds retain_on_delete to S3 sub-resources, adds force_delete to ECR repositories with documentation comment
infrastructure/Pulumi.production.yaml Adds randomSuffix as encrypted Pulumi secret, removes YAML document separator

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread infrastructure/Pulumi.production.yaml
Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@infrastructure/__main__.py`:
- Line 50: The exported S3 bucket Outputs (data_bucket.bucket and
model_artifacts_bucket.bucket) are tainted secret because random_suffix is
created with stack_config.require_secret("randomSuffix"); fix this by calling
.unsecret() on the bucket name Outputs before exporting them (i.e., wrap the
Outputs you pass to pulumi.export or any final export variable with
.unsecret()), ensuring the exports return the plain bucket names rather than
“[secret]”. Locate uses of data_bucket.bucket and model_artifacts_bucket.bucket
in the export/exporting block (exports around where aws_s3_data_bucket_name and
aws_s3_model_artifacts_bucket_name are set) and apply Output.unsecret() to those
outputs.

In `@maskfile.md`:
- Around line 196-200: The export of S3 bucket names is currently secret-tainted
because random_suffix is loaded with require_secret (random_suffix) and
concatenated into data_bucket.bucket and artifacts_bucket.bucket, causing
pulumi.stack output to return [secret]; fix this in __main__.py by unsecreting
the Outputs before exporting—wrap the bucket name Outputs with
pulumi.Output.unsecret() (e.g., pulumi.Output.unsecret(data_bucket.bucket) and
pulumi.Output.unsecret(artifacts_bucket.bucket)) so aws_s3_data_bucket_name and
aws_s3_model_artifacts_bucket_name exports are not secret-tainted.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 268b99d and 629fb84.

📒 Files selected for processing (3)
  • infrastructure/Pulumi.production.yaml
  • infrastructure/__main__.py
  • maskfile.md

Comment thread infrastructure/__main__.py
Comment thread maskfile.md
Comment thread infrastructure/__main__.py
coderabbitai[bot]
coderabbitai Bot previously approved these changes Feb 25, 2026
Copy link
Copy Markdown
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: 2

♻️ Duplicate comments (2)
infrastructure/__main__.py (2)

1799-1803: LGTM — pulumi.Output.unsecret() correctly strips the secret taint before export.

This addresses the previously flagged issue: stack outputs aws_s3_data_bucket_name and aws_s3_model_artifacts_bucket_name will now return the plain bucket name instead of [secret], unblocking the dependent maskfile.md commands.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infrastructure/__main__.py` around lines 1799 - 1803, Exports currently wrap
data_bucket.bucket and model_artifacts_bucket.bucket with pulumi.Output.unsecret
to remove the secret taint before exporting; ensure the pulumi.export calls use
pulumi.Output.unsecret for both exports (the pulumi.export lines and the
pulumi.Output.unsecret(...) calls referencing data_bucket and
model_artifacts_bucket) so stack outputs return plain bucket names instead of
"[secret]".

1799-1803: LGTM — pulumi.Output.unsecret() correctly strips the secret taint before export.

This addresses the previously flagged issue: stack outputs aws_s3_data_bucket_name and aws_s3_model_artifacts_bucket_name will now return the plain bucket name instead of [secret].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infrastructure/__main__.py` around lines 1799 - 1803, Wrap the S3 bucket
output values with pulumi.Output.unsecret so exported stack outputs return plain
bucket names; specifically ensure aws_s3_data_bucket_name and
aws_s3_model_artifacts_bucket_name use
pulumi.Output.unsecret(data_bucket.bucket) and
pulumi.Output.unsecret(model_artifacts_bucket.bucket) respectively (using the
pulumi.Output.unsecret API) and apply the same pattern to any other exported
secret-tainted outputs you find.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@infrastructure/__main__.py`:
- Line 50: After calling stack_config.require_secret("randomSuffix") and
assigning to random_suffix, validate that random_suffix is not an empty string
and fail fast if it is; add a guard immediately after the assignment (checking
if random_suffix == "" or if not random_suffix.strip()) and raise a clear
exception (or exit with an error) that mentions the missing/empty randomSuffix
so downstream bucket-name construction (e.g., the fund-data- and
fund-model-artifacts- suffix usage) cannot produce unintended empty suffixes.
- Line 50: Validate that the secret returned by
stack_config.require_secret("randomSuffix") is non-empty by applying a guard
function: create a small validator (e.g., _assert_non_empty_suffix) that raises
a ValueError if the suffix is an empty string and use .apply on the Pulumi
secret Output (random_suffix =
stack_config.require_secret("randomSuffix").apply(_assert_non_empty_suffix)) so
the empty value is rejected at runtime and downstream uses of random_suffix
(bucket names, IAM ARNs, exported outputs) cannot silently degrade.

---

Duplicate comments:
In `@infrastructure/__main__.py`:
- Around line 1799-1803: Exports currently wrap data_bucket.bucket and
model_artifacts_bucket.bucket with pulumi.Output.unsecret to remove the secret
taint before exporting; ensure the pulumi.export calls use
pulumi.Output.unsecret for both exports (the pulumi.export lines and the
pulumi.Output.unsecret(...) calls referencing data_bucket and
model_artifacts_bucket) so stack outputs return plain bucket names instead of
"[secret]".
- Around line 1799-1803: Wrap the S3 bucket output values with
pulumi.Output.unsecret so exported stack outputs return plain bucket names;
specifically ensure aws_s3_data_bucket_name and
aws_s3_model_artifacts_bucket_name use
pulumi.Output.unsecret(data_bucket.bucket) and
pulumi.Output.unsecret(model_artifacts_bucket.bucket) respectively (using the
pulumi.Output.unsecret API) and apply the same pattern to any other exported
secret-tainted outputs you find.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 629fb84 and 5cbb2f7.

📒 Files selected for processing (1)
  • infrastructure/__main__.py

Comment thread infrastructure/__main__.py
@forstmeier
Copy link
Copy Markdown
Collaborator Author

Coveralls failed because the service is down externally.

@chrisaddy chrisaddy merged commit e257323 into master Feb 25, 2026
10 of 12 checks passed
@chrisaddy chrisaddy deleted the infrastructure-down-command-fixes branch February 25, 2026 17:12
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Overview Feb 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

markdown Markdown code updates python Python code updates

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants