Skip to content

fix(aws): harden CloudFormation BYOC releases#179

Open
alongubkin wants to merge 7 commits into
mainfrom
alon/alien-320-harden-aws-cloudformation-byoc-release-path
Open

fix(aws): harden CloudFormation BYOC releases#179
alongubkin wants to merge 7 commits into
mainfrom
alon/alien-320-harden-aws-cloudformation-byoc-release-path

Conversation

@alongubkin

@alongubkin alongubkin commented Jul 23, 2026

Copy link
Copy Markdown
Member

Summary

  • emit valid NextGen OpenSearch Serverless and storage CORS CloudFormation resources
  • preserve deployer input values and include transitive native-addon bytes in build cache keys
  • avoid unauthenticated bootstrap OTLP export when runtime secrets are vault-backed
  • parse raw storage keys before signing so reserved characters are encoded exactly once

Validation

  • focused OpenSearch and storage CloudFormation generator tests
  • AWS CloudFormation ValidateTemplate and real create/update deployment proof
  • real AWS NextGen collection-group deployment: Generation: NEXTGEN, zero minimum indexing/search OCU, on.aws endpoint
  • full locally built application proof through Platform pnpm dev: TLS/health, send, asynchronous indexing, full-text search hit, and content retrieval
  • focused native storage-path and transitive-cache tests
  • focused worker-runtime OTLP test plus deployed cold-start/export proof
  • cargo check --locked -p alien-bindings-node

Linear: ALIEN-320

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown

Greptile Summary

This PR applies several targeted hardening fixes to AWS CloudFormation BYOC releases across four distinct problem areas. It is well-scoped with focused tests and real-environment validation proofs for each fix.

  • SES permission fix: email/manage-identities now includes the configuration-set ARN in both stack and resource IAM bindings, resolving an AccessDenied on ses:PutEmailIdentityConfigurationSetAttributes (AWS routes that call against the configuration-set ARN, not just the identity ARN).
  • OpenSearch NextGen: The CloudFormation emitter now emits AWS::OpenSearchServerless::CollectionGroup with Generation: NEXTGEN, optional per-component OCU capacity limits, and proper collection-group dependency ordering; the binding ref exports endpoint and collectionName only (next-gen collections have no dashboard endpoint attribute).
  • Storage CORS: Adds S3 CORS rule emission when corsAllowedOrigins is configured; hardcoded to GET/HEAD methods for browser download via presigned URLs, exposing only the ETag header.
  • OTLP deferred init: Avoids attaching an unauthenticated OpenTelemetryTracingBridge during process bootstrap when ALIEN_RUNTIME_SECRETS is present; the authenticated provider is installed later via init_otlp_logging_from_config after vault resolution.
  • Storage path parsing + build cache: Pre-parses storage object keys before presigning (single encoding of reserved characters), and now includes transitive native-addon bytes in artifact cache keys.

Confidence Score: 5/5

This PR is safe to merge. Each fix is narrowly scoped, has dedicated tests, and was validated against real AWS environments.

All four problem areas (SES permission scope, OpenSearch NextGen CloudFormation, OTLP bootstrap deferral, storage presign encoding) are addressed with targeted changes. The permission expansion in manage-identities correctly adds only the required configuration-set ARN without broadening identity scopes. The OTLP deferral logic is sound: it avoids capturing a stale unauthenticated provider in the tracing bridge while still delivering authenticated exports after vault resolution via the dynamically-read OTLP_PROVIDER. The build cache key change hashes addon file bytes (not just paths), which is the right unit of cache invalidation. No logic paths are left unguarded.

No files require special attention.

Important Files Changed

Filename Overview
crates/alien-permissions/permission-sets/email/manage-identities.jsonc Adds configuration-set ARNs to both stack and resource IAM bindings so ses:PutEmailIdentityConfigurationSetAttributes is authorized against the configuration-set ARN as AWS requires.
crates/alien-cloudformation/src/emitters/aws/open_search.rs Emits AWS::OpenSearchServerless::CollectionGroup with Generation: NEXTGEN, optional CapacityLimits, collection group dependency, and corrected binding/import refs (no DashboardEndpoint for next-gen collections).
crates/alien-cloudformation/src/emitters/aws/storage.rs Adds CorsConfiguration emission when corsAllowedOrigins is non-empty; methods hardcoded to GET/HEAD, exposed headers limited to ETag — matches the described presigned-read-URL use case.
crates/alien-worker-runtime/src/otlp.rs Defers OTLP tracing bridge creation when ALIEN_RUNTIME_SECRETS is present, preventing an unauthenticated provider from being captured at subscriber construction time before vault credentials are resolved.
crates/alien-bindings-node/src/storage.rs Adds parse_path helper that validates and parses raw storage keys through object_store::path::Path before presigning, ensuring reserved characters are percent-encoded exactly once.
crates/alien-build/src/lib.rs Extends TypeScript artifact cache key to include bytes (not just path) of transitive native addons reached via sdk/node_modules, so addon updates correctly invalidate the cache.
crates/alien-worker-runtime/src/runtime.rs Calls init_otlp_logging_from_config after vault secret resolution so the authenticated OTLP provider is stored before any function output is emitted; ALIEN_COMMANDS_TOKEN and ALIEN_RUNTIME_SECRETS are stripped from the child process environment.
crates/alien-core/src/resources/aws_open_search.rs Adds AwsOpenSearchCapacity/CapacityRange structs with validate_capacity() enforcing AWS OCU increment rules; collectionType immutability guard moved to apply_update.
crates/alien-cli/src/commands/deploy.rs DG-token deployment path now passes resolved input_values through to_sdk_stack_input_values so deployer inputs are preserved; adds string-list JSON array parsing for --input.

Sequence Diagram

sequenceDiagram
    participant CLI as alien CLI
    participant Runtime as Worker Runtime
    participant Vault as Secret Vault
    participant OTLP as OTLP Endpoint
    participant Lambda as Lambda Runtime API
    participant App as App Process

    CLI->>Lambda: Deploy (CloudFormation stack with CollectionGroup/CORS/SES permissions)
    Lambda->>Runtime: Cold start

    Note over Runtime: init_otlp_logging()<br/>ALIEN_RUNTIME_SECRETS present?
    alt vault-backed secrets present
        Runtime-->>Runtime: Defer OTLP bridge (return None)
    else no vault secrets
        Runtime->>OTLP: Initialize tracing bridge (unauthenticated endpoint only)
    end

    Runtime->>Lambda: Register extension (pre-start)
    Runtime->>Vault: load_vault("secrets") → OTEL_EXPORTER_OTLP_HEADERS
    Vault-->>Runtime: auth header value
    Runtime->>OTLP: init_otlp_logging_from_config (authenticated)

    Runtime->>App: Start subprocess (ALIEN_RUNTIME_SECRETS stripped)
    App-->>Runtime: stdout/stderr lines
    Runtime->>OTLP: emit_log (reads OTLP_PROVIDER dynamically)

    App->>Runtime: ses:PutEmailIdentityConfigurationSetAttributes
    Note over Runtime: IAM Resource now includes<br/>configuration-set ARN ✅
Loading

Reviews (3): Last reviewed commit: "fix(aws): allow runtime identities to us..." | Re-trigger Greptile

export const StorageSchema = z.object({
"id": z.string().describe("Name of the the storage bucket.\nFor names with dots, each dot-separated label must be ≤ 63 characters."),
"corsAllowedOrigins": z.optional(z.array(z.string()).describe("Browser origins allowed to read objects through signed URLs.\n\nWhen non-empty, providers configure CORS for `GET` and `HEAD` requests.\nAn origin of `*` is appropriate for private buckets whose signed URLs\nare bearer credentials and do not use browser cookies.\nDefault: `[]` (CORS disabled).")),
"id": z.string().describe("Name of the the storage bucket.\nFor names with dots, each dot-separated label must be ≤ 63 characters."),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Generated file drops indentation for id field

The newly added corsAllowedOrigins property is indented (4 spaces) but "id" and the remaining pre-existing properties ("publicRead", "versioning") have zero indentation. This is a generator artifact: the tool appears to emit consistent indentation only for the first alphabetical property. TypeScript and Zod parse the file correctly, so this has no runtime impact, but it points to an inconsistency in the code generator that may resurface as the schema grows.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/src/generated/zod/storage-schema.ts
Line: 14

Comment:
**Generated file drops indentation for `id` field**

The newly added `corsAllowedOrigins` property is indented (4 spaces) but `"id"` and the remaining pre-existing properties (`"publicRead"`, `"versioning"`) have zero indentation. This is a generator artifact: the tool appears to emit consistent indentation only for the first alphabetical property. TypeScript and Zod parse the file correctly, so this has no runtime impact, but it points to an inconsistency in the code generator that may resurface as the schema grows.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@alongubkin
alongubkin force-pushed the alon/alien-320-harden-aws-cloudformation-byoc-release-path branch 2 times, most recently from f9e9801 to d0e58d7 Compare July 23, 2026 02:18
@alongubkin
alongubkin force-pushed the alon/alien-320-harden-aws-cloudformation-byoc-release-path branch from d0e58d7 to b1d404a Compare July 23, 2026 02:31
@alongubkin

Copy link
Copy Markdown
Member Author

Final AWS validation update:

  • Live OpenSearch Serverless rejected 1 OCU for both indexing and search; the supported nonzero floor is 2. Validation/schema and the CloudFormation fixture now enforce that before deployment (4229ed78, 3a45a908).
  • The generated CloudFormation setup path updated a real NEXTGEN collection group to min indexing/search 2.0 OCU; the stack reached UPDATE_COMPLETE. The runtime manager correctly refused to mutate the frozen setup-owned capacity.
  • Real Lambda testing exposed that an 8-second pre-poll readiness budget could still cross Lambda’s 10-second init limit. 22c1bcc3 now polls the Runtime API immediately and keeps readiness waiting inside invocation handling. A cold API invocation had one init (1334.03 ms), HTTP 200, and no init timeout/restart.
  • A cold events invocation initialized once (1165.78 ms) and a deliberately unmatched valid SQS event returned FunctionError: Unhandled / TASK_DELIVERY_FAILED, proving failures are no longer silently acknowledged.
  • Focused results: OpenSearch core 8/8, CloudFormation generator 7/7, TypeScript core 67/67, AWS runtime 80/80. Fresh CI is running on 3a45a908.

@alongubkin

Copy link
Copy Markdown
Member Author

@greptileai

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