Skip to content

Local dev + Dependabot + SES infra fixes - #459

Merged
lkacenja merged 3 commits into
devfrom
infra-localstack-pip-ses
Jun 26, 2026
Merged

Local dev + Dependabot + SES infra fixes#459
lkacenja merged 3 commits into
devfrom
infra-localstack-pip-ses

Conversation

@lkacenja

@lkacenja lkacenja commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Three small, independent infra/dev-tooling fixes.

1. LocalStack requires an auth token (local dev)

LocalStack's unified image (2026.03.0+) now requires LOCALSTACK_AUTH_TOKEN. docker-compose.yml now passes it through and fails fast with actionable guidance when unset, instead of the cryptic exit-code-55 license error. Set it via a gitignored .env or your shell. (CfA qualifies for a free LocalStack OSS license.)

2. Dependabot now monitors the Python components

Added a pip ecosystem covering all six python_components/* manifests (accessibility_scan, ci, classifier, crawler, document_inference, evaluation). Previously only bundler/npm/github-actions were watched, so Python deps got zero update PRs or security alerts.

3. SES: pin module to stop key rotation

Root cause of the recurring red deploys: terraform/modules/ses/main.tf referenced cloudposse/terraform-aws-ses with no version ref (floating HEAD). An older module version created an auto-expiring SMTP access key (awsutils_expiring_iam_access_key, 30-day max_age); current upstream creates a plain non-rotating aws_iam_access_key. The floating ref made plans nondeterministic and triggered an expiring→regular key migration in CI that needs iam:DeleteAccessKey/iam:CreateAccessKey — permissions the GitHub Actions role intentionally lacks.

Fix: pin to v0.25.2, which uses iam-system-user 1.2.1 — a stable, non-rotating access key (iam_create_access_key defaults to true, so the SMTP key is still created). No max_age knob is needed; that variable does not exist in v0.25.2. The pin makes plans deterministic and matches what CI was already migrating toward. The old auto-rotation delivered no benefit anyway — it wrote to SSM, disconnected from the Secrets Manager values the app actually reads.

Validation

  • Dependabot YAML parses (4 ecosystems, 6 pip directories)
  • SES module pinned to v0.25.2; verified v0.25.2 + iam-system-user 1.2.1 create a non-rotating key with no max_age argument (an earlier iam_access_key_max_age = 0 attempt failed tofu plan and was removed)
  • LocalStack compose interpolation verified both with and without the token set

🤖 Generated with Claude Code

lkacenja and others added 2 commits June 26, 2026 08:57
LocalStack's unified image (2026.03.0+) requires an auth token. Pass it
through from the environment and fail fast with actionable guidance when
it's unset, instead of the cryptic exit-code-55 license error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a pip ecosystem covering all six python_components manifests so their
dependencies get update PRs and security alerts, closing the gap where
only bundler/npm/actions were watched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread .github/dependabot.yml
open-pull-requests-limit: 10
cooldown:
default-days: 7
- package-ecosystem: pip

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dependabot pip entries added without requiring or referencing lockfiles or hashed requirements; add/verify lockfiles (with hashes) for '/python_components/*' to prevent silent upgrades.

Details

✨ AI Reasoning
​The added pip update block enables Dependabot for multiple python_components directories but does not enforce or reference lockfile usage or checksum verification (e.g., requirements.txt with hashes or Pipfile.lock). Enabling automated updates without ensuring lockfile/hash-based installs can allow silent upgrades that the rule aims to prevent. The change is confined to the new pip configuration lines in the dependabot.yml diff.

🔧 How do I fix it?
Include lockfiles in your repo and CI. Pin exact versions or SHAs in manifests. Enable checksum verification. Set ignore-scripts in npm or equivalent. Enforce a 72hr minimum package age policy to avoid newly published malicious packages.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

module "ses" {
name = "${var.project_name}-${var.environment}-ses"
source = "github.com/cloudposse/terraform-aws-ses"
source = "github.com/cloudposse/terraform-aws-ses?ref=v0.25.2"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

module source pinned to tag '?ref=v0.25.2' but not to an immutable commit SHA or checksum; prefer a commit SHA (or checksum) for stronger immutability.

Details

✨ AI Reasoning
​The change sets module source to a GitHub ref query using a tag (v0.25.2) rather than an immutable commit SHA or including checksum verification. This aims to improve determinism over floating HEAD, but still allows the tag to be repointed or replaced in some workflows and lacks checksum validation. The edit occurs on the module source line and is the only change to the module's dependency declaration in this diff.

🔧 How do I fix it?
Include lockfiles in your repo and CI. Pin exact versions or SHAs in manifests. Enable checksum verification. Set ignore-scripts in npm or equivalent. Enforce a 72hr minimum package age policy to avoid newly published malicious packages.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

@lkacenja lkacenja self-assigned this Jun 26, 2026
terraform/modules/ses/main.tf referenced cloudposse/terraform-aws-ses
with no version ref (floating HEAD). An older module version created an
auto-expiring SMTP access key (awsutils_expiring_iam_access_key, 30-day
max_age); current upstream creates a plain non-rotating aws_iam_access_key.
The floating ref made plans nondeterministic and triggered an
expiring->regular key migration in CI that needs iam:DeleteAccessKey/
CreateAccessKey -- permissions the GitHub Actions role intentionally lacks.

Pin to v0.25.2, which uses iam-system-user 1.2.1: a stable, non-rotating
access key (iam_create_access_key defaults to true). No max_age knob is
needed -- that variable does not exist in v0.25.2.

Note: the expiring->regular switch is a one-time replacement requiring
privileged IAM creds (not the CI role), and rotates the SMTP credentials,
so SMTP_USER/SMTP_PASSWORD in Secrets Manager must be updated from the new
key or outbound email breaks. After that single apply, CI deploys go green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lkacenja
lkacenja force-pushed the infra-localstack-pip-ses branch from 02fb5fc to 04c9666 Compare June 26, 2026 15:12
@lkacenja

Copy link
Copy Markdown
Contributor Author

Re: Aikido — "pip entries added without requiring/referencing lockfiles or hashed requirements."

Acknowledged, and we're accepting this for now with the following rationale:

  • Direct dependencies are already exact-pinned (==) in all six python_components requirements.txt files (verified: 0 loose/range specifiers). So this change introduces no new drift — it only adds Dependabot update PRs + security alerts on top of an already-pinned set, which is a strict improvement over the prior state where these components had no monitoring at all.
  • The real residual gaps the finding points at are (1) unpinned transitive dependencies and (2) no hash verification (pip install without --require-hashes). Both are legitimate but are pre-existing, not introduced here.
  • Closing them properly means generating fully-resolved hashed lockfiles (uv pip compile --generate-hashes) for each component and switching the Dockerfiles to --require-hashes, plus rebuilding/verifying all six images. That's a separate hardening effort that shouldn't block enabling dependency monitoring, and we're tracking it independently rather than expanding the scope of this PR.

Net effect of this PR for the Python components: more visibility and alerting, no reduction in safety.

@lkacenja
lkacenja merged commit d8abb0c into dev Jun 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant