chore(deps)(deps-dev): bump vitest from 4.1.0 to 4.1.7 in the vitest group across 1 directory#28
Open
dependabot[bot] wants to merge 1 commit into
Open
Conversation
julia-kafarska
added a commit
that referenced
this pull request
May 25, 2026
* fix(canvas): correct snap target + drag-snap stickiness for Custom Domain rows
Two bugs in connection drag:
1. dragCompatibility positions used getPortAnchorPoint (schema's
side-distribution math) instead of getSocketCanvasPosition, so the
snap target Y on Custom Domain row ports drifted progressively
from the visible dot (~50px on row 0, ~0px on the last row).
2. snap was computed from currentPoint, which itself is set to the
snapped port's position. Distance-to-self stayed at 0 so the snap
locked onto the first port that ever won. Added cursorPoint to
DrawingConnectionState and compute snap from it; currentPoint
remains the visible (snapped or cursor) wire endpoint.
* refactor(secret-store): schema-driven 1->N deploy expansion
Properties + deploy model rebuilt around the canonical schema:
- Properties: name -> "Store name"; secrets list -> new `secret_bindings`
field with two inputs per row (env-var key ← upstream ref); auto_rotate
dropped (was inert + wrong-scoped). Bindings explained: the block does
NOT hold secret values — values live in the cloud secret manager.
- Schema: add optional `iceType` and `deployExpansion` to
HighLevelResource. Secret Store declares
`deployExpansion: { partitionBy: 'bindings', nameFrom: { field: 'ref',
fallback: 'key' }, labelFrom: 'key', tagPerEntry: ... }`.
- Lookup: getHighLevelResourceByIceType helper with a cached index.
- Generic pass: new deploy/passes/deploy-expansion.ts emits one cloud
resource per partition entry, dedup'd within/across blocks, forwarding
provider-shaped properties verbatim. Knows nothing about secrets.
- Translator: the previous `if (iceType === 'Security.Secret')` branch
is replaced with `if (schemaResource?.deployExpansion)` — cardinal
rule, no iceType hardcoded in cross-cutting code.
Adding AWS Secrets Manager or Azure Key Vault requires only an extractor
+ handler for the provider's resource type. Adding a new expanding block
requires only a `deployExpansion` declaration on its schema entry.
* refactor(canvas-renderer): drop hardcoded iceType branches via SPECIAL_NODE_RENDERERS table
Audit item #11 — cardinal rule violation. The dispatcher had three
hardcoded `if (iceType === 'X')` branches for Custom Domain, Reroute,
and Private Network, each wiring a bespoke component with its own
prop set + innerKey formula.
Consolidated into a single declarative `SPECIAL_NODE_RENDERERS` table
keyed by iceType, with factory entries that own their own component
AND innerKey formula. The dispatcher iterates this table generically
— no iceType-specific code paths remain. Adding a new bespoke renderer
extends the table; the dispatcher stays unchanged.
Dispatch order preserved by construction: the special table is
consulted BEFORE the container check so PrivateNetwork (a container
we render with a custom header) and Reroute (which the classifier
calls a container despite being a pass-through dot) hit their
bespoke factories first.
Tests: locked-in entries list + per-entry contract (element + innerKey)
+ innerKey-changes-on-relevant-data assertions for Custom Domain
(routes count) and PrivateNetwork (ingress mode).
* refactor(canvas-path): drop hardcoded iceType in socket-position via BESPOKE_SOCKET_POSITIONS table
Audit item #12 — cardinal rule violation. `getSocketCanvasPosition`
had an `if (iceType === 'Network.CustomDomain' && socketId.startsWith
('domain-out-'))` branch that resolved the bespoke row-Y for per-route
ports.
Consolidated into a `BESPOKE_SOCKET_POSITIONS` table keyed by iceType,
with resolver entries returning `Point | null` (null = fall through to
the standard layout). The dispatcher iterates this table generically
— no iceType branches in the resolver function. New bespoke layouts
register here; dispatch stays unchanged.
Tests: locked-in entries list, per-resolver contract (returns null on
miss), and dispatcher behaviour (bespoke hit, fall-through, dangling
socket id).
* refactor(properties): schema-drive tab visibility + deployment-target skip
Audit item #13 — cardinal rule violation. The tab builder and the
deployment-target card both branched on hardcoded iceType strings:
- build-visible-tabs.ts:41-46 — config tab visible for 4 iceTypes
- build-visible-tabs.ts:53 — domain tab visible for 2 iceTypes
- build-visible-tabs.ts:56 — source tab visible for Source.Repository
- node-properties-section.tsx:166 — deployment target hidden for 2 iceTypes
Consolidated into a single declarative table
`BLOCK_PROPERTY_PANEL_CONFIGS` keyed by iceType, with per-block
`forceTabs` and `skipDeploymentTarget` flags. Both the builder and the
panel iterate this table generically — no iceType branches remain.
Adding a bespoke panel experience adds an entry; both call sites pick
it up.
Per-tab SECTION rendering (CustomDomainPanel, EnvVarsEditor, etc.)
inside the panel body is still iceType-conditioned — covered by audit
item #14 in the next commit, which extends this same config table.
* refactor(properties): schema-drive per-tab section dispatch via SECTION_COMPONENTS
Audit item #14 — cardinal rule violation. The panel body had six
hardcoded `iceType === 'X'` branches choosing which bespoke section
component to render inside which tab:
- domain tab: PublicEndpointDomainSection / CustomDomainPanel
- config tab: EnvVarsEditor / CustomDomainPanel / PrivateNetworkPanel
/ MonitoringLogSection
- source tab: SourceRepositorySection
- config tab fallback: SourceRepositorySection when no source tab
Extended BLOCK_PROPERTY_PANEL_CONFIGS with a `sections: Record<TabId,
SectionId[]>` field. Each iceType declares which sections render under
which tabs; the new SECTION_COMPONENTS factory map renders them.
`renderSectionsForTab(iceType, tab, ctx)` is the generic dispatcher
the JSX calls — no iceType branches remain.
Dropped the dead `visibleTabs.length <= 1 && iceType === 'Source.
Repository'` config-tab fallback: with the source tab now always forced
for that block via forceTabs, the fallback could never fire.
Tests: per-iceType set + section-id-tab validity check.
* refactor(canvas-sizing): schema-drive bespoke node sizing via BESPOKE_NODE_SIZING table
Audit item #16 — cardinal rule violation. computeNodeSizes had three
hardcoded iceType checks driving the width/height/fold dispatch:
- isCustomDomain = iceType === 'Network.CustomDomain'
- isPrivateNetwork = isPrivateNetworkIce(iceType)
- isCronJob = iceType === 'Compute.CronJob'
Plus 4 nested ternaries threading those flags through width, height,
expandedHeight, and visualHeight.
Consolidated into BESPOKE_NODE_SIZING — a Record<iceType,
BespokeSizingEntry> where each entry owns its width function, height
function, and an `alwaysExpanded` flag that opts the block out of
folding (so dynamic content like Custom Domain route slots can't
collapse to a pill).
The dispatcher does a single table lookup, falls through to the
compact-node helpers when no bespoke entry exists, and respects
`alwaysExpanded` uniformly. No iceType branches remain.
Tests: locked-in entries list + alwaysExpanded invariant.
* refactor(deploy/edge-classifier): schema-drive isolation + standalone classification
Audit items #5 + #6 — cardinal rule violations. Three hardcoded
iceType checks in cross-cutting classifier code:
- edge-classifier.ts:65 — `parent.data?.iceType === 'Network.PrivateNetwork'`
in the ancestor walk
- edge-classifier.ts:90 — guard: `iceType !== 'Network.CustomDomain'`
- edge-classifier.ts:93 — `parent.iceType !== 'Network.PrivateNetwork'`
in the standalone-mode check
Introduced `BLOCK_DEPLOY_CLASSIFIERS` — a per-iceType flag table with
two flags:
- `isolatesNetworkContext`: this iceType is a network-isolation
container (services nested inside should be internal-only)
- `metadataOnlyWhenStandalone`: this iceType has two deploy modes
based on parent context (metadata-only standalone vs. deployable
when nested in an isolation container)
Renamed predicates to match the generic shape:
- `hasPrivateNetworkAncestor` -> `hasNetworkIsolatingAncestor`
- `isCustomDomainStandalone` -> `isStandaloneMetadataOnly`
Old names kept as `@deprecated` aliases so external callers and tests
don't break. Card-translator call sites switched to the new names.
Adding a new isolation container or a new standalone/nested block
adds a table entry; classifier code stays unchanged.
* refactor(deploy/passes): schema-drive public-ingress detection + domain propagation
Audit items #7 + #8 — cardinal rule violations in two passes:
- pass-1-5-endpoint-wiring.ts:107-114 — inline `isEndpointIceType`
branched on Network.PublicEndpoint AND Network.CustomDomain (with
nested-in-PrivateNetwork check) to identify ingress endpoints
- pass-1-45-domain-propagation.ts:55-58 — hardcoded srcIce / dstIce
=== 'Network.CustomDomain' to route domain propagation
Extended BLOCK_DEPLOY_CLASSIFIERS with two new flags:
- `publicIngressMode`: 'always' (PublicEndpoint) or
'when-nested-in-isolated-network' (CustomDomain — only counts as
ingress when nested inside an isolatesNetworkContext container)
- `isDomainPropagator`: true for CustomDomain — generic name so any
future domain-source block can flow through the same pass
Added generic `isPublicIngressNode(node, allNodes)` predicate to
edge-classifier that reads the flag table. Refactored pass-1-5 to
call it; pass-1-45 reads `isDomainPropagator` directly. No iceType
strings remain in either pass.
Tests: 3 new flag assertions + 5 new isPublicIngressNode behaviour
cases (always-mode, standalone CD, nested-in-isolated-network, nested-
in-non-isolation, plain compute).
* refactor(deploy/security-rules): schema-drive iceType classifiers via SECURITY_ROLES table
Audit item #15 — cardinal rule violation. The pre-deploy security
scanner had 9+ tiny iceType-comparing classifier functions
(`isDatabase`, `isStorage`, `isGateway`, `isService`, `isAuth`,
`isSecret`, `isMonitoring`, `isVpc`, `isSubnet`, `isPrivateNetwork`,
`isVpcLike`), each inlining its own `iceType === 'X'` check.
Consolidated into a schema-shaped role table:
- `SECURITY_ROLES_BY_ICE_TYPE`: per-iceType role list
- `SECURITY_ROLES_BY_PREFIX`: category-prefix inheritance
(Database./Compute./Monitoring.* automatically pick up their role
without per-iceType table edits)
- `hasSecurityRole(iceType, role)`: the single lookup function the
classifier readers call
Classifier functions remain as thin one-line role readers; rule
evaluation code is unchanged. New blocks that need a security role
add an entry to the table.
Split the previous `isVpcLike` into two distinct roles:
`isolatesNestedChildren` (VPC + Subnet + PrivateNetwork — used by the
ancestor check) and `topLevelNetworkBoundary` (VPC + PrivateNetwork
only — used by Rule 6, where a Subnet at the canvas root doesn't
isolate anything). The original code conflated these into a single
overloaded helper.
* refactor(classifiers): unify connection-rules + propagation-rules iceType classifiers via shared @ice/constants table
Audit items #9 + #10 — cardinal rule violations across two packages.
Both `@ice/types/connection-rules/predicates.ts` and
`@ice/core/compute/propagation-rules.ts` had ~15 identical-ish
classifier functions (isBackend, isFrontend, isDatabase, isCache,
isStorage, isQueue, isSecrets, isCustomDomain, …), each duplicating
the same regex + prefix + exact-match bodies. The propagation-rules
copy carried a comment apologising for the duplication ("Minimal
copies of the classifiers from @ice/types/connection-rules. Kept
local to avoid cross-package moduleResolution conflicts.").
Introduced `@ice/constants/block-classifiers.ts` as the single source
of truth — a three-tier role table:
- `BLOCK_ROLES_BY_ICE_TYPE`: exact iceType -> roles
- `BLOCK_ROLES_BY_PREFIX`: category prefix -> role (Compute.*,
Database.*, Storage.*, Messaging.*,
Monitoring.*, Log.*)
- `BLOCK_ROLES_BY_REGEX`: legacy provider-specific iceTypes
(PostgreSQL/Redis/Bucket/Worker/…)
authored under varied namespaces
`hasBlockRole(t, role)` queries all three tiers. Both packages import
it — `predicates.ts` and `propagation-rules.ts` predicate bodies are
now one-line lookups, no iceType strings remain in classifier code.
Adding a new role/iceType binding edits ONE table; both connection-
rules and propagation-rules pick it up automatically.
Tests: full equivalence preserved (4664 tests pass) + new
block-classifiers test suite covering exact / prefix / regex /
composite / negative cases + table integrity.
* refactor(deploy): dedup SERVICE_BACKEND_ICE_TYPES via shared serviceBackend role
Audit items #17 + #18 — duplicated static set in two cross-cutting
locations:
- edge-classifier.ts:34-40 — exported SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS
- pass-1-5-endpoint-wiring.ts:188-194 — local SERVICE_BACKEND_ICE_TYPES
Both held the same 5 iceTypes (Compute.Container/BackendAPI/SSRSite/
Worker/ServerlessFunction). Two copies, two sources of drift.
Added a new `serviceBackend` role to the shared classifier table in
@ice/constants. The 5 iceTypes register the role via
BLOCK_ROLES_BY_ICE_TYPE — Compute.StaticSite is intentionally
excluded (compiles to backendBucket via Firebase Hosting, not a NEG).
- edge-classifier exports SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS as a
thin materialisation derived from the role table (kept for callers
that want `.has(t)` membership).
- pass-1-5-endpoint-wiring.ts now uses `hasBlockRole(t, 'serviceBackend')`
directly; its inline duplicate set is gone.
New iceTypes register the role in ONE table; both consumers pick it up.
* refactor(translator): drop hardcoded iceType + provider branches via type-map + override table
Audit items #1 + #2 — two critical violations in the otherwise-
provider-agnostic translator:
- card-translator.ts:227 — `ice_type === 'Network.CustomDomain'
? 'gcp.compute.globalForwardingRule' : type_map[ice_type]`
(iceType AND GCP-specific in one cross-cutting line)
- card-translator.ts:313-322 — `if (gcp_type === 'gcp.run.service')
... else if (gcp_type === 'aws.ecs.service') ... else if
(gcp_type === 'azure.containerapp.containerApp') ...` cascade
applying provider-specific internal-mode mutations inline
#1: Added Network.CustomDomain to each provider's type-map (mirrors
PublicEndpoint — the nested CD acts as the network's gateway and
compiles to the same ingress chain on every provider; standalone CDs
are filtered earlier by isStandaloneMetadataOnly). Translator now does
a plain `type_map[ice_type]` lookup — no iceType branches.
#2: Introduced `internal-ingress-overrides.ts` — a per-provider
mutator table keyed by resolved resource type:
- gcp.run.service -> ingress=internal-and-cloud-load-balancing, allow_unauthenticated=false
- aws.ecs.service -> assign_public_ip=false, internal=true
- azure.containerapp.containerApp -> ingress_external=false
Translator calls `applyInternalIngressOverride(resource_type, props)`
generically. The `SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS.has(t)` set
membership is replaced with `hasBlockRole(t, 'serviceBackend')` per
the earlier dedup commit. No provider strings or iceType strings
appear in the translator's body.
New providers add an override entry; the translator stays unchanged.
Tests: existing type-map entry counts bumped by 1 + new CustomDomain
mapping assertions per provider + new internal-ingress-overrides
suite (table contents + per-provider behaviour + no-op fallthrough).
* refactor(deploy): drop hardcoded Compute.StaticSite in storage extractor + endpoint pass
Audit items #3 + #4 — last two cardinal-rule violations:
- pass-1-5-endpoint-wiring.ts:204 — `if (be.targetIceType === 'Compute.StaticSite')`
skipped LB wiring for static-site backends (GCP-Firebase-Hosting-specific behaviour)
- extractors/network.ts:25 — `iceType === 'Compute.StaticSite'` flipped a Storage.Bucket
extractor's `public_access` + `website_hosting` when the bucket backs a static site
Two schema-shaped declarations replace them, each scoped to its
natural layer:
#3 -> `self-serving-resources.ts`: a new `SELF_SERVING_PUBLIC_RESOURCES`
set keyed by RESOLVED PROVIDER RESOURCE TYPE (gcp.firebase.hosting
today; future: aws.amplify.app, azure.staticwebapps.staticSite).
The endpoint-wiring pass reads `targetGraphNode.type` and calls
`isSelfServingPublicResource(...)` — no iceType strings.
#4 -> New `publicWebsiteSource` role on the shared
`BLOCK_ROLES_BY_ICE_TYPE` table. Compute.StaticSite registers
this role; the storage extractor reads it via
`hasBlockRole(iceType, 'publicWebsiteSource')`. Adding a future
static-site-style block (Compute.JamstackSite, …) adds one
table entry — extractor stays unchanged.
Tests:
- existing pass-1-5 fixtures updated to mark static-site graph nodes
with `type: 'gcp.firebase.hosting'` (the resolved type the new
check reads); behavioural assertions unchanged
- new self-serving-resources test suite covering registered +
negative cases
With this commit, every audit item in the schema-driven-refactor
punch list is shipped.
* refactor(deploy/aws): modularise AWSDeployer to mirror gcp/ shape
Phase 0 of the AWS deploy buildout. The previous 496-LOC monolithic
aws-deployer.ts is replaced with the same dispatch shape the GCP
deployer uses:
providers/aws/
aws-deployer.ts — thin dispatcher + HANDLER_REGISTRY map
types.ts — AWSHandlerContext + AWSResourceHandler
sdk-loader.ts — load_aws_sdk + initialize_aws_clients + destroy
index.ts — barrel
handlers/
ec2.ts — migrated from aws-deployer.ts (no behaviour change)
s3.ts — migrated (account-id suffix arrives in commit #8)
lambda.ts — migrated (S3-ref only; auto-build in commit #28)
The old `providers/aws-deployer.ts` becomes a re-export shim so the
existing import paths in `providers/index.ts` and the test suite keep
resolving without edits.
Cardinal-rule schema-driven: HANDLER_REGISTRY is the single declarative
fact for "which handler runs for which resource type". The dispatcher
iterates it generically; no `if (type === 'aws.X')` branches. Adding
the next ~17 AWS services is now register-an-entry + drop-a-file.
Behaviour preserved verbatim — all 64 existing AWS deployer tests pass
unchanged (one minor wording fix in the dispatcher to match the
original "Unsupported resource type for creation/update/deletion"
phrasing the test suite pins).
* feat(deploy/aws): extractors for compute (ecs.service, lambda.function, events.rule)
Phase 1 commit 1/5 — first AWS extractor module.
extractors/aws/compute.ts (new):
- extract_ecs_service_properties ← Compute.Container, Compute.BackendAPI,
Compute.SSRSite, Compute.Worker
- extract_lambda_function_properties ← Compute.ServerlessFunction
- extract_events_rule_properties ← Compute.CronJob
extractors/dispatch.ts:
Register the 3 extractors under their resolved aws.* resource types.
Adds the first AWS section to PROPERTY_EXTRACTORS.
Provider parity notes (extractor only — handlers come later):
- ECS multi-port uses the shared parse_exposed_ports() so the canvas
contract matches what Cloud Run sees today.
- Lambda accepts the nested code.{s3Bucket,s3Key} shape AND falls
through to the flat s3_bucket / s3_key fields for back-compat with
the existing Lambda test harness. Auto-build from Source.Repository
lands in commit #28.
- EventBridge cron is the 6-field format (not unix 5-field). The
named "daily"/"hourly"/"weekly"/"monthly" presets that GCP Cloud
Scheduler accepts are normalised to the AWS expression so cards
stay provider-portable.
Tests: 24 new assertions covering defaults, passthrough, exposed_ports
parsing, code-source shape variants, cron preset normalisation. The
dispatch table test gets a new shape — counts GCP entries (27)
separately from AWS (>=3, will grow with commits #3–#6), accepts
aws.* keys in the {provider}.{service}.{kind} regex.
* feat(deploy/aws): extractors for database (rds, dynamodb, elasticache, docdb)
Phase 1 commit 2/5.
extractors/aws/database.ts (new):
- extract_rds_db_instance_properties ← Database.PostgreSQL, MySQL
- extract_dynamodb_table_properties ← Database.DynamoDB
- extract_elasticache_cluster_properties ← Database.Redis
- extract_docdb_cluster_properties ← Database.MongoDB
extractors/dispatch.ts: register all 4 under aws.* resource types.
Provider parity:
- RDS engine + version inferred from iceType + runtime string, same
rule the GCP Cloud SQL extractor uses -> cards stay portable.
- master_user_password defaults to '' so the handler fails loudly
rather than provisioning RDS / DocDB with no real credential.
- ElastiCache exposes ELASTICACHE_REDIS_SIZE_MAP for the canvas
M-series enum (M1 -> cache.t3.micro, M5 -> cache.m5.xlarge ×2 for HA
parity with GCP STANDARD_HA).
- DynamoDB defaults to PAY_PER_REQUEST (AWS-recommended for new
workloads); PROVISIONED branch emits RCU/WCU only when set.
15 new test assertions across the four resources covering engine
detection, version extraction, size-enum translation, billing-mode
branching, and password defaults.
* feat(deploy/aws): extractors for network (s3, apigateway, cloudfront, elbv2)
Phase 1 commit 3/5.
extractors/aws/network.ts (new):
- extract_s3_bucket_properties ← Storage.Bucket / Storage.ObjectStorage / Compute.StaticSite
- extract_api_gateway_rest_api_properties ← Network.Gateway
- extract_cloudfront_distribution_properties ← Network.PublicEndpoint / Network.CustomDomain
- extract_elbv2_load_balancer_properties ← Network.LoadBalancer
extractors/dispatch.ts: register all 4 under aws.* resource types.
Cross-provider parity:
- S3 reads the publicWebsiteSource role from the shared block-
classifier table; same flip-policy the GCP cloud_storage extractor
uses for Compute.StaticSite. Plain Storage.Bucket stays private.
- CloudFront defaults to HTTPS + auto-cert + PriceClass_100 (most-
common cost-aware preset). Cert provisioning in us-east-1 is the
handler's job in commit #19.
- ELBv2 defaults to internet-facing ALB on HTTPS:443; flips to
`internal` scheme when `internal: true` (parity with the
INTERNAL_INGRESS_OVERRIDES table semantics).
11 new tests + dispatch table assertion updated (the previous
"aws.s3.bucket is intentionally absent" assertion is replaced with
a generic "aws.unknown.thing" check now that S3 has landed).
* feat(deploy/aws): extractors for ancillary (sqs, sns, cognito, secrets, cw-logs)
Phase 1 commit 4/5.
extractors/aws/ancillary.ts (new):
- extract_sqs_queue_properties ← Messaging.Queue
- extract_sns_topic_properties ← Messaging.Topic / CloudPubSub
- extract_cognito_user_pool_properties ← Security.Identity
- extract_secrets_manager_secret_properties ← Security.Secret
- extract_cloudwatch_log_group_properties ← Monitoring.Log
extractors/dispatch.ts: register all 5 under aws.* resource types.
Notable:
- SQS content_based_deduplication is only emitted on FIFO queues
(AWS rejects the field on standard SQS).
- Secrets Manager extractor forwards data.secrets as `bindings` —
same shape the schema-declared deploy-expansion pass already uses
for GCP Secret Manager. Adding AWS doesn't require translator
changes; the same expansion branch fires.
- Cognito reads both signInProviders (canvas camelCase) and
sign_in_providers (snake) so projects authored with either work.
14 new test assertions.
* feat(deploy/aws): extractors for AI/analytics (opensearch, bedrock, sagemaker, redshift)
Phase 1 commit 5/5 — last extractor module. Every aws.* resource type
in AWS_TYPE_MAP now has a registered property extractor.
extractors/aws/ai.ts (new):
- extract_opensearch_domain_properties ← AI.VectorDB
- extract_bedrock_endpoint_properties ← AI.LLMGateway
- extract_sagemaker_endpoint_properties ← AI.ModelServing
- extract_redshift_cluster_properties ← Analytics.DataWarehouse
extractors/dispatch.ts: register all 4 under aws.* resource types.
Notable defaults:
- OpenSearch starts cost-conscious: single t3.small.search node with
encryption-at-rest + node-to-node encryption on. Production users
flip dedicated_master_enabled + bump instance_count ≥ 3.
- Bedrock defaults to on-demand Claude 3 Haiku (zero provisioned
model units -> handler emits no resource). Provisioned throughput
fires only when model_units > 0.
- SageMaker defaults to a real-time ml.t2.medium endpoint.
- Redshift defaults to a single-node dc2.large with the no-default-
password invariant the RDS + DocDB extractors share.
12 new test assertions. With this commit Phase 1 is complete:
PROPERTY_EXTRACTORS table now has 27 GCP + 20 AWS entries.
* feat(deploy/aws): shared infra — STS account-id resolver + IAM ensure-role helper
Phase 2 commit 1 — the shared helpers later handlers depend on.
providers/aws/account.ts (new):
- create_account_id_resolver(region): memoised STS GetCallerIdentity
caller. First call hits STS, subsequent calls return cached value.
Concurrent first-calls coalesce into one STS request. Throws a
clear "install @aws-sdk/client-sts" message when SDK is absent.
providers/aws/iam-roles.ts (new):
- ensureManagedRole(region, roleName, trustPolicyJson, managedPolicyArn):
idempotent GetRole -> CreateRole-on-NoSuchEntity -> AttachRolePolicy
pattern. Returns the role ARN. Tolerates already-attached
policies (AlreadyExists swallowed; any other error fatal).
- ensureEcsTaskExecutionRole(region): convenience wrapper for the
standard Fargate execution role (consumed by the ECS handler in
commit #23).
providers/aws/types.ts:
AWSHandlerContext gains `ensure_account_id: AccountIdResolver` —
handlers `await ctx.ensure_account_id()` to get the cached id.
providers/aws/aws-deployer.ts:
initialize() wires the resolver into the context. A pre-init stub
throws "called before initialize()" if a handler tries to use it
out of band.
providers/aws/index.ts: re-export the new helpers.
Tests: 9 new — memoisation, concurrent-call coalescing, missing-SDK
error path, missing-Account-field error path, ensureManagedRole
happy-path + create-on-miss + IAM-SDK-missing path.
* feat(deploy/aws): s3 handler — account-id suffix + publicWebsite bucket policy
Handler #8 in Phase 2.
Two upgrades over the Phase 0 baseline:
1. **Account-id suffix.** S3 bucket names are globally unique
across all AWS accounts. The handler awaits ctx.ensure_account_id()
and appends `-{accountId}` to the translator's resource name
before any SDK call. `ice-myapp-bucket` becomes
`ice-myapp-bucket-111122223333`, eliminating the global-collision
class. The provider_id ARN carries the post-suffix name so
update + delete round-trip cleanly (bucket_name_from_arn parses
it back out).
2. **publicWebsite policy.** When the extractor sets `public_access`
+ `website_hosting` (today only Compute.StaticSite triggers this
via the publicWebsiteSource role from the shared classifier
table), the handler runs a 4-step create:
CreateBucket
-> PutPublicAccessBlock (loosen account-default block)
-> PutBucketPolicy (attach the public-read policy)
-> PutBucketWebsite (set index/404 pages)
Plain Storage.Bucket skips all three follow-up commands.
Tests:
- Existing test harness extended with a makeStsModule mock + a
FAKE_ACCOUNT_ID constant; the makeFullRegistry now installs STS
alongside the SDK clients.
- All existing S3 ARN assertions updated to expect the suffixed form.
- 3 new tests: account-id suffix lock-in, public-website 4-step
sequence with policy + website config, plain-bucket negative path.
64 -> 67 AWS deployer tests passing.
* feat(deploy/aws): lambda handler — fail-fast role + code-source validation
Handler #9 in Phase 2.
Hardens the existing Lambda S3-ref handler with two pre-create
validations that turn cryptic AWS API errors into clear messages:
1. **IAM role required.** The AWS SDK returns "Could not find
resource ..." when CreateFunction is called with an empty Role
ARN. The handler now refuses up front with:
"Lambda function requires an IAM execution role ARN
(properties.role). Wire one in or use the auto-role helper."
2. **Code source required.** When neither s3_bucket + s3_key NOR a
base64 zip_file is supplied, the handler refuses with:
"Lambda function code source is missing. Provide
properties.code.{s3Bucket,s3Key} or zip_file (auto-build from
Source.Repository lands in a later commit)."
Both checks fire before any SDK call, so the failure surfaces in the
deployer's `error` field with full context instead of as an opaque
AWS error.
Tests updated so happy-path Lambda create tests now pass both role
and code source. 2 new tests pin the fail-fast paths.
* feat(deploy/aws): cloudwatch-logs handler + shared _result helpers
Handler #10 in Phase 2.
providers/aws/handlers/cloudwatch-logs.ts (new):
- aws.cloudwatch.logGroup handler — CreateLogGroup +
PutRetentionPolicy (when retention_in_days set) on create.
PutRetentionPolicy on update. DeleteLogGroup on delete.
providers/aws/handlers/_result.ts (new):
- ok / err / sdkMissing helpers shared across all AWS handlers.
Stops the per-handler result/fail boilerplate copy-paste.
providers/aws/sdk-loader.ts: load @aws-sdk/client-cloudwatch-logs
under the 'cloudwatch-logs' client key.
providers/aws/aws-deployer.ts: register cloudwatch_logs_handler
in HANDLER_REGISTRY.
Tests: 3 new — create-with-retention, create-without-retention skips
PutRetentionPolicy, delete sequence. Test harness extended with
makeCloudWatchLogsModule + corresponding FakeImportRegistry entry.
* feat(deploy/aws): secrets-manager handler + shared test harness
Handler #11 in Phase 2.
providers/aws/handlers/secrets-manager.ts (new):
- aws.secretsmanager.secret handler. Mirrors the GCP Secret
Manager contract: the schema-declared deploy-expansion pass
emits one Secret per binding row; this handler just creates /
updates / deletes ONE. Values are NOT written (operators
populate via AWS console/CLI — same security tradeoff as GCP).
- delete uses ForceDeleteWithoutRecovery=true (skips the 30-day
recovery window — appropriate when ICE removes the binding).
providers/aws/sdk-loader.ts: load @aws-sdk/client-secrets-manager
under the 'secrets-manager' client key.
providers/aws/aws-deployer.ts: register secrets_manager_handler.
providers/__tests__/_aws-test-harness.ts (new):
Extracts the Function-constructor stub + generic SDK-mock factory
out of the original aws-deployer.test.ts so per-handler test
files stay small. Strips the trailing 'Command' from command
class names when building the __cmd label so assertions read the
operation name (`CreateSecret`, not `CreateSecretCommand`).
providers/__tests__/aws-secrets-manager.test.ts (new): 4 focused
tests — create returns the SDK ARN, update + delete sequences,
SDK-not-installed path.
* feat(deploy/aws): sqs handler — CreateQueue/SetQueueAttributes/DeleteQueue, FIFO .fifo suffix
Handler #12 in Phase 2. Standard + FIFO queues. FIFO queues get the
.fifo suffix appended to the name automatically (AWS enforces). 3
focused tests.
* feat(deploy/aws): sns handler — CreateTopic/SetTopicAttributes/DeleteTopic, FIFO .fifo suffix
* feat(deploy/aws): dynamodb handler — CreateTable + key schema + PITR
* feat(deploy/aws): elasticache handler — single-node + replication-group paths
* feat(deploy/aws): rds handler — no-default-password gate + provisioning poll
Handler #16 in Phase 2. CreateDBInstance + 20-min status-poll loop
that respects ctx.abort_signal and reports progress via on_step.
Refuses to create when master_user_password is empty (parity with
the extractor's no-default-password invariant).
* feat(deploy/aws): docdb handler — cluster + per-instance creation
* feat(deploy/aws): cognito handler — user pool with password policy + MFA
* feat(deploy/aws): cloudfront handler — us-east-1 ACM cert + minimal distribution
Handler #19. CloudFront requires ACM certs in us-east-1 regardless
of deploy region; the handler spins up a one-shot ACM client pinned
to us-east-1 for RequestCertificate, then attaches the ARN to the
distribution's ViewerCertificate. Falls back to CloudFrontDefaultCertificate
when ACM SDK is absent.
* feat(deploy/aws): elbv2 handler — LB + skeleton target group
* feat(deploy/aws): api-gateway handler — REST API + default-stage deployment
* feat(deploy/aws): events-rule handler (CronJob) — PutRule + PutTargets
* feat(deploy/aws): ecs handler — auto-cluster + task role + service create
Handler #23. Compute.Container 'just works' on AWS — the handler
idempotently bootstraps ecsTaskExecutionRole + ice-default-cluster
before RegisterTaskDefinition + CreateService. Mirrors the GCP
Cloud Run UX (no cluster to think about).
* feat(deploy/aws): opensearch handler — CreateDomain with cluster/EBS/encryption config
* feat(deploy/aws): bedrock handler — on-demand no-op + provisioned-throughput create
* feat(deploy/aws): sagemaker handler — EndpointConfig + Endpoint, requires model_name
* feat(deploy/aws): redshift handler — CreateCluster + no-default-password gate
* feat(deploy/aws): lambda auto-build from Source.Repository
Phase 3 (commit #28). When a Compute.ServerlessFunction block has a
connected Source.Repository AND no explicit S3 ref, the handler
auto-builds the zip and uploads it before CreateFunction:
1. git clone --depth 1 --branch <branch> <repo>
2. npm install --omit=dev (skipped if no package.json)
3. zip -qr function.zip .
4. PutObject to ice-bootstrap-{accountId}-{region}/lambda/{name}/{ts}.zip
(HeadBucket -> CreateBucket if absent)
5. Stamp s3_bucket + s3_key onto properties and continue.
Local-only — assumes git/npm/zip on the deploy host. AWS CodeBuild
integration deferred to a future commit. Existing manual S3-ref + zip
paths are unchanged; the auto-build branch only fires when
`properties.repository` is set AND no explicit code source exists.
* test(deploy/aws): unskip AWS Type Map block + end-to-end coverage
Phase 4 commit #29. With every aws.* resource type registered in
PROPERTY_EXTRACTORS (commits #2–#6), the AWS Type Map test block can
finally turn on. Expanded the iceType matrix from 5 to 19 entries
covering every AWS-mapped block.
New end-to-end test wires Compute.StaticSite + Security.Secret (with
two bindings — exercising the schema-declared deploy-expansion pass)
+ Database.PostgreSQL into a single translator call, asserts the
resulting graph has 4 deployables resolving to s3.bucket /
secretsmanager.secret×2 / rds.dbInstance. The Azure block remains
skipped (deferred to a future Azure handler buildout).
* docs(deploy/aws): provider notes — quirks, assumptions, deferred work
Phase 4 commit #30 — final commit of the AWS buildout.
providers/aws/README.md documents the AWS-specific decisions the 30
commits in this series bake in:
- architecture (mirrors gcp/, schema-driven HANDLER_REGISTRY)
- S3 account-id suffix
- CloudFront us-east-1 cert
- ECS auto-cluster + task role
- RDS / DocDB / Redshift no-default-password invariant
- RDS provisioning poll
- Lambda auto-build flow (git + npm + zip + bootstrap S3)
- Bedrock on-demand no-op
- Secrets Manager values-never-written contract
- SQS / SNS .fifo suffix
- SDK packages as optional peer deps
- test harness layout
- deferred work (VPC blocks, CodeBuild, drift detection, LocalStack)
Read this before changing any AWS handler.
* feat(aws): selectively enable safe categories via feature flags
Flip PROVIDER_FLAGS.aws.enabled to true with a hand-picked category
map (Storage, Messaging, Cache, Monitoring, Security, Source, Config).
Compute / Frontend / Scheduler / Network / Database / AI / Analytics
stay gated until their concrete unblockers land — ECS VPC blocks,
CloudFront cert-validation flow, update-paths, etc.
README.md gets a Rollout state table documenting why each gated
category is held back and what unblocks it.
Integrity test in packages/constants asserts the per-category map
stays exhaustive, so future CategoryId additions force a deliberate
on/off decision here.
* fix(palette): enable provider dropdown items when any block is available
Replace the project-provider lock on the palette provider dropdown
with an availability check: a provider option is selectable iff at
least one concept has it in providers and its category is enabled
for that provider.
Before: in a GCP project, AWS was greyed in the palette dropdown
even after AWS feature-flag enabled — so users couldn't browse the
AWS catalog from a GCP project.
After: AWS opens as long as it has any available block under the
current PROVIDER_FLAGS — drag-into-project compatibility remains
enforced at the canvas-drop layer.
availableProviderIds is derived in resource-palette.tsx from the
unfiltered component list using isCategoryEnabledForProvider — same
schema-driven gate the component filter already uses.
* docs(architecture): explain how canvas edges become cloud infra
New page docs/architecture/connections-to-cloud.md walks the five-layer
pipeline (connection-rules -> propagation -> type-maps -> extractors ->
handlers) and grounds it with two worked GCP examples:
- Storage.Bucket -> Compute.BackendAPI: env-var injection + IAM binding,
no edge resource in GCP.
- Compute.CronJob -> Compute.BackendAPI: Cloud Scheduler HTTP target +
run.invoker IAM binding.
Links the new page from architecture/README.md and the existing
core-engine.md "Computing flows" section so readers landing on either
find their way to the deep dive.
* docs(architecture): explain how canvas edges become cloud infra
julia-kafarska
added a commit
that referenced
this pull request
May 25, 2026
* fix(canvas): correct snap target + drag-snap stickiness for Custom Domain rows
Two bugs in connection drag:
1. dragCompatibility positions used getPortAnchorPoint (schema's
side-distribution math) instead of getSocketCanvasPosition, so the
snap target Y on Custom Domain row ports drifted progressively
from the visible dot (~50px on row 0, ~0px on the last row).
2. snap was computed from currentPoint, which itself is set to the
snapped port's position. Distance-to-self stayed at 0 so the snap
locked onto the first port that ever won. Added cursorPoint to
DrawingConnectionState and compute snap from it; currentPoint
remains the visible (snapped or cursor) wire endpoint.
* refactor(secret-store): schema-driven 1→N deploy expansion
Properties + deploy model rebuilt around the canonical schema:
- Properties: name → "Store name"; secrets list → new `secret_bindings`
field with two inputs per row (env-var key ← upstream ref); auto_rotate
dropped (was inert + wrong-scoped). Bindings explained: the block does
NOT hold secret values — values live in the cloud secret manager.
- Schema: add optional `iceType` and `deployExpansion` to
HighLevelResource. Secret Store declares
`deployExpansion: { partitionBy: 'bindings', nameFrom: { field: 'ref',
fallback: 'key' }, labelFrom: 'key', tagPerEntry: ... }`.
- Lookup: getHighLevelResourceByIceType helper with a cached index.
- Generic pass: new deploy/passes/deploy-expansion.ts emits one cloud
resource per partition entry, dedup'd within/across blocks, forwarding
provider-shaped properties verbatim. Knows nothing about secrets.
- Translator: the previous `if (iceType === 'Security.Secret')` branch
is replaced with `if (schemaResource?.deployExpansion)` — cardinal
rule, no iceType hardcoded in cross-cutting code.
Adding AWS Secrets Manager or Azure Key Vault requires only an extractor
+ handler for the provider's resource type. Adding a new expanding block
requires only a `deployExpansion` declaration on its schema entry.
* refactor(canvas-renderer): drop hardcoded iceType branches via SPECIAL_NODE_RENDERERS table
Audit item #11 — cardinal rule violation. The dispatcher had three
hardcoded `if (iceType === 'X')` branches for Custom Domain, Reroute,
and Private Network, each wiring a bespoke component with its own
prop set + innerKey formula.
Consolidated into a single declarative `SPECIAL_NODE_RENDERERS` table
keyed by iceType, with factory entries that own their own component
AND innerKey formula. The dispatcher iterates this table generically
— no iceType-specific code paths remain. Adding a new bespoke renderer
extends the table; the dispatcher stays unchanged.
Dispatch order preserved by construction: the special table is
consulted BEFORE the container check so PrivateNetwork (a container
we render with a custom header) and Reroute (which the classifier
calls a container despite being a pass-through dot) hit their
bespoke factories first.
Tests: locked-in entries list + per-entry contract (element + innerKey)
+ innerKey-changes-on-relevant-data assertions for Custom Domain
(routes count) and PrivateNetwork (ingress mode).
* refactor(canvas-path): drop hardcoded iceType in socket-position via BESPOKE_SOCKET_POSITIONS table
Audit item #12 — cardinal rule violation. `getSocketCanvasPosition`
had an `if (iceType === 'Network.CustomDomain' && socketId.startsWith
('domain-out-'))` branch that resolved the bespoke row-Y for per-route
ports.
Consolidated into a `BESPOKE_SOCKET_POSITIONS` table keyed by iceType,
with resolver entries returning `Point | null` (null = fall through to
the standard layout). The dispatcher iterates this table generically
— no iceType branches in the resolver function. New bespoke layouts
register here; dispatch stays unchanged.
Tests: locked-in entries list, per-resolver contract (returns null on
miss), and dispatcher behaviour (bespoke hit, fall-through, dangling
socket id).
* refactor(properties): schema-drive tab visibility + deployment-target skip
Audit item #13 — cardinal rule violation. The tab builder and the
deployment-target card both branched on hardcoded iceType strings:
- build-visible-tabs.ts:41-46 — config tab visible for 4 iceTypes
- build-visible-tabs.ts:53 — domain tab visible for 2 iceTypes
- build-visible-tabs.ts:56 — source tab visible for Source.Repository
- node-properties-section.tsx:166 — deployment target hidden for 2 iceTypes
Consolidated into a single declarative table
`BLOCK_PROPERTY_PANEL_CONFIGS` keyed by iceType, with per-block
`forceTabs` and `skipDeploymentTarget` flags. Both the builder and the
panel iterate this table generically — no iceType branches remain.
Adding a bespoke panel experience adds an entry; both call sites pick
it up.
Per-tab SECTION rendering (CustomDomainPanel, EnvVarsEditor, etc.)
inside the panel body is still iceType-conditioned — covered by audit
item #14 in the next commit, which extends this same config table.
* refactor(properties): schema-drive per-tab section dispatch via SECTION_COMPONENTS
Audit item #14 — cardinal rule violation. The panel body had six
hardcoded `iceType === 'X'` branches choosing which bespoke section
component to render inside which tab:
- domain tab: PublicEndpointDomainSection / CustomDomainPanel
- config tab: EnvVarsEditor / CustomDomainPanel / PrivateNetworkPanel
/ MonitoringLogSection
- source tab: SourceRepositorySection
- config tab fallback: SourceRepositorySection when no source tab
Extended BLOCK_PROPERTY_PANEL_CONFIGS with a `sections: Record<TabId,
SectionId[]>` field. Each iceType declares which sections render under
which tabs; the new SECTION_COMPONENTS factory map renders them.
`renderSectionsForTab(iceType, tab, ctx)` is the generic dispatcher
the JSX calls — no iceType branches remain.
Dropped the dead `visibleTabs.length <= 1 && iceType === 'Source.
Repository'` config-tab fallback: with the source tab now always forced
for that block via forceTabs, the fallback could never fire.
Tests: per-iceType set + section-id-tab validity check.
* refactor(canvas-sizing): schema-drive bespoke node sizing via BESPOKE_NODE_SIZING table
Audit item #16 — cardinal rule violation. computeNodeSizes had three
hardcoded iceType checks driving the width/height/fold dispatch:
- isCustomDomain = iceType === 'Network.CustomDomain'
- isPrivateNetwork = isPrivateNetworkIce(iceType)
- isCronJob = iceType === 'Compute.CronJob'
Plus 4 nested ternaries threading those flags through width, height,
expandedHeight, and visualHeight.
Consolidated into BESPOKE_NODE_SIZING — a Record<iceType,
BespokeSizingEntry> where each entry owns its width function, height
function, and an `alwaysExpanded` flag that opts the block out of
folding (so dynamic content like Custom Domain route slots can't
collapse to a pill).
The dispatcher does a single table lookup, falls through to the
compact-node helpers when no bespoke entry exists, and respects
`alwaysExpanded` uniformly. No iceType branches remain.
Tests: locked-in entries list + alwaysExpanded invariant.
* refactor(deploy/edge-classifier): schema-drive isolation + standalone classification
Audit items #5 + #6 — cardinal rule violations. Three hardcoded
iceType checks in cross-cutting classifier code:
- edge-classifier.ts:65 — `parent.data?.iceType === 'Network.PrivateNetwork'`
in the ancestor walk
- edge-classifier.ts:90 — guard: `iceType !== 'Network.CustomDomain'`
- edge-classifier.ts:93 — `parent.iceType !== 'Network.PrivateNetwork'`
in the standalone-mode check
Introduced `BLOCK_DEPLOY_CLASSIFIERS` — a per-iceType flag table with
two flags:
- `isolatesNetworkContext`: this iceType is a network-isolation
container (services nested inside should be internal-only)
- `metadataOnlyWhenStandalone`: this iceType has two deploy modes
based on parent context (metadata-only standalone vs. deployable
when nested in an isolation container)
Renamed predicates to match the generic shape:
- `hasPrivateNetworkAncestor` → `hasNetworkIsolatingAncestor`
- `isCustomDomainStandalone` → `isStandaloneMetadataOnly`
Old names kept as `@deprecated` aliases so external callers and tests
don't break. Card-translator call sites switched to the new names.
Adding a new isolation container or a new standalone/nested block
adds a table entry; classifier code stays unchanged.
* refactor(deploy/passes): schema-drive public-ingress detection + domain propagation
Audit items #7 + #8 — cardinal rule violations in two passes:
- pass-1-5-endpoint-wiring.ts:107-114 — inline `isEndpointIceType`
branched on Network.PublicEndpoint AND Network.CustomDomain (with
nested-in-PrivateNetwork check) to identify ingress endpoints
- pass-1-45-domain-propagation.ts:55-58 — hardcoded srcIce / dstIce
=== 'Network.CustomDomain' to route domain propagation
Extended BLOCK_DEPLOY_CLASSIFIERS with two new flags:
- `publicIngressMode`: 'always' (PublicEndpoint) or
'when-nested-in-isolated-network' (CustomDomain — only counts as
ingress when nested inside an isolatesNetworkContext container)
- `isDomainPropagator`: true for CustomDomain — generic name so any
future domain-source block can flow through the same pass
Added generic `isPublicIngressNode(node, allNodes)` predicate to
edge-classifier that reads the flag table. Refactored pass-1-5 to
call it; pass-1-45 reads `isDomainPropagator` directly. No iceType
strings remain in either pass.
Tests: 3 new flag assertions + 5 new isPublicIngressNode behaviour
cases (always-mode, standalone CD, nested-in-isolated-network, nested-
in-non-isolation, plain compute).
* refactor(deploy/security-rules): schema-drive iceType classifiers via SECURITY_ROLES table
Audit item #15 — cardinal rule violation. The pre-deploy security
scanner had 9+ tiny iceType-comparing classifier functions
(`isDatabase`, `isStorage`, `isGateway`, `isService`, `isAuth`,
`isSecret`, `isMonitoring`, `isVpc`, `isSubnet`, `isPrivateNetwork`,
`isVpcLike`), each inlining its own `iceType === 'X'` check.
Consolidated into a schema-shaped role table:
- `SECURITY_ROLES_BY_ICE_TYPE`: per-iceType role list
- `SECURITY_ROLES_BY_PREFIX`: category-prefix inheritance
(Database./Compute./Monitoring.* automatically pick up their role
without per-iceType table edits)
- `hasSecurityRole(iceType, role)`: the single lookup function the
classifier readers call
Classifier functions remain as thin one-line role readers; rule
evaluation code is unchanged. New blocks that need a security role
add an entry to the table.
Split the previous `isVpcLike` into two distinct roles:
`isolatesNestedChildren` (VPC + Subnet + PrivateNetwork — used by the
ancestor check) and `topLevelNetworkBoundary` (VPC + PrivateNetwork
only — used by Rule 6, where a Subnet at the canvas root doesn't
isolate anything). The original code conflated these into a single
overloaded helper.
* refactor(classifiers): unify connection-rules + propagation-rules iceType classifiers via shared @ice/constants table
Audit items #9 + #10 — cardinal rule violations across two packages.
Both `@ice/types/connection-rules/predicates.ts` and
`@ice/core/compute/propagation-rules.ts` had ~15 identical-ish
classifier functions (isBackend, isFrontend, isDatabase, isCache,
isStorage, isQueue, isSecrets, isCustomDomain, …), each duplicating
the same regex + prefix + exact-match bodies. The propagation-rules
copy carried a comment apologising for the duplication ("Minimal
copies of the classifiers from @ice/types/connection-rules. Kept
local to avoid cross-package moduleResolution conflicts.").
Introduced `@ice/constants/block-classifiers.ts` as the single source
of truth — a three-tier role table:
- `BLOCK_ROLES_BY_ICE_TYPE`: exact iceType → roles
- `BLOCK_ROLES_BY_PREFIX`: category prefix → role (Compute.*,
Database.*, Storage.*, Messaging.*,
Monitoring.*, Log.*)
- `BLOCK_ROLES_BY_REGEX`: legacy provider-specific iceTypes
(PostgreSQL/Redis/Bucket/Worker/…)
authored under varied namespaces
`hasBlockRole(t, role)` queries all three tiers. Both packages import
it — `predicates.ts` and `propagation-rules.ts` predicate bodies are
now one-line lookups, no iceType strings remain in classifier code.
Adding a new role/iceType binding edits ONE table; both connection-
rules and propagation-rules pick it up automatically.
Tests: full equivalence preserved (4664 tests pass) + new
block-classifiers test suite covering exact / prefix / regex /
composite / negative cases + table integrity.
* refactor(deploy): dedup SERVICE_BACKEND_ICE_TYPES via shared serviceBackend role
Audit items #17 + #18 — duplicated static set in two cross-cutting
locations:
- edge-classifier.ts:34-40 — exported SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS
- pass-1-5-endpoint-wiring.ts:188-194 — local SERVICE_BACKEND_ICE_TYPES
Both held the same 5 iceTypes (Compute.Container/BackendAPI/SSRSite/
Worker/ServerlessFunction). Two copies, two sources of drift.
Added a new `serviceBackend` role to the shared classifier table in
@ice/constants. The 5 iceTypes register the role via
BLOCK_ROLES_BY_ICE_TYPE — Compute.StaticSite is intentionally
excluded (compiles to backendBucket via Firebase Hosting, not a NEG).
- edge-classifier exports SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS as a
thin materialisation derived from the role table (kept for callers
that want `.has(t)` membership).
- pass-1-5-endpoint-wiring.ts now uses `hasBlockRole(t, 'serviceBackend')`
directly; its inline duplicate set is gone.
New iceTypes register the role in ONE table; both consumers pick it up.
* refactor(translator): drop hardcoded iceType + provider branches via type-map + override table
Audit items #1 + #2 — two critical violations in the otherwise-
provider-agnostic translator:
- card-translator.ts:227 — `ice_type === 'Network.CustomDomain'
? 'gcp.compute.globalForwardingRule' : type_map[ice_type]`
(iceType AND GCP-specific in one cross-cutting line)
- card-translator.ts:313-322 — `if (gcp_type === 'gcp.run.service')
... else if (gcp_type === 'aws.ecs.service') ... else if
(gcp_type === 'azure.containerapp.containerApp') ...` cascade
applying provider-specific internal-mode mutations inline
#1: Added Network.CustomDomain to each provider's type-map (mirrors
PublicEndpoint — the nested CD acts as the network's gateway and
compiles to the same ingress chain on every provider; standalone CDs
are filtered earlier by isStandaloneMetadataOnly). Translator now does
a plain `type_map[ice_type]` lookup — no iceType branches.
#2: Introduced `internal-ingress-overrides.ts` — a per-provider
mutator table keyed by resolved resource type:
- gcp.run.service → ingress=internal-and-cloud-load-balancing, allow_unauthenticated=false
- aws.ecs.service → assign_public_ip=false, internal=true
- azure.containerapp.containerApp → ingress_external=false
Translator calls `applyInternalIngressOverride(resource_type, props)`
generically. The `SERVICE_BACKEND_ICE_TYPES_FOR_INGRESS.has(t)` set
membership is replaced with `hasBlockRole(t, 'serviceBackend')` per
the earlier dedup commit. No provider strings or iceType strings
appear in the translator's body.
New providers add an override entry; the translator stays unchanged.
Tests: existing type-map entry counts bumped by 1 + new CustomDomain
mapping assertions per provider + new internal-ingress-overrides
suite (table contents + per-provider behaviour + no-op fallthrough).
* refactor(deploy): drop hardcoded Compute.StaticSite in storage extractor + endpoint pass
Audit items #3 + #4 — last two cardinal-rule violations:
- pass-1-5-endpoint-wiring.ts:204 — `if (be.targetIceType === 'Compute.StaticSite')`
skipped LB wiring for static-site backends (GCP-Firebase-Hosting-specific behaviour)
- extractors/network.ts:25 — `iceType === 'Compute.StaticSite'` flipped a Storage.Bucket
extractor's `public_access` + `website_hosting` when the bucket backs a static site
Two schema-shaped declarations replace them, each scoped to its
natural layer:
#3 → `self-serving-resources.ts`: a new `SELF_SERVING_PUBLIC_RESOURCES`
set keyed by RESOLVED PROVIDER RESOURCE TYPE (gcp.firebase.hosting
today; future: aws.amplify.app, azure.staticwebapps.staticSite).
The endpoint-wiring pass reads `targetGraphNode.type` and calls
`isSelfServingPublicResource(...)` — no iceType strings.
#4 → New `publicWebsiteSource` role on the shared
`BLOCK_ROLES_BY_ICE_TYPE` table. Compute.StaticSite registers
this role; the storage extractor reads it via
`hasBlockRole(iceType, 'publicWebsiteSource')`. Adding a future
static-site-style block (Compute.JamstackSite, …) adds one
table entry — extractor stays unchanged.
Tests:
- existing pass-1-5 fixtures updated to mark static-site graph nodes
with `type: 'gcp.firebase.hosting'` (the resolved type the new
check reads); behavioural assertions unchanged
- new self-serving-resources test suite covering registered +
negative cases
With this commit, every audit item in the schema-driven-refactor
punch list is shipped.
* refactor(deploy/aws): modularise AWSDeployer to mirror gcp/ shape
Phase 0 of the AWS deploy buildout. The previous 496-LOC monolithic
aws-deployer.ts is replaced with the same dispatch shape the GCP
deployer uses:
providers/aws/
aws-deployer.ts — thin dispatcher + HANDLER_REGISTRY map
types.ts — AWSHandlerContext + AWSResourceHandler
sdk-loader.ts — load_aws_sdk + initialize_aws_clients + destroy
index.ts — barrel
handlers/
ec2.ts — migrated from aws-deployer.ts (no behaviour change)
s3.ts — migrated (account-id suffix arrives in commit #8)
lambda.ts — migrated (S3-ref only; auto-build in commit #28)
The old `providers/aws-deployer.ts` becomes a re-export shim so the
existing import paths in `providers/index.ts` and the test suite keep
resolving without edits.
Cardinal-rule schema-driven: HANDLER_REGISTRY is the single declarative
fact for "which handler runs for which resource type". The dispatcher
iterates it generically; no `if (type === 'aws.X')` branches. Adding
the next ~17 AWS services is now register-an-entry + drop-a-file.
Behaviour preserved verbatim — all 64 existing AWS deployer tests pass
unchanged (one minor wording fix in the dispatcher to match the
original "Unsupported resource type for creation/update/deletion"
phrasing the test suite pins).
* feat(deploy/aws): extractors for compute (ecs.service, lambda.function, events.rule)
Phase 1 commit 1/5 — first AWS extractor module.
extractors/aws/compute.ts (new):
- extract_ecs_service_properties ← Compute.Container, Compute.BackendAPI,
Compute.SSRSite, Compute.Worker
- extract_lambda_function_properties ← Compute.ServerlessFunction
- extract_events_rule_properties ← Compute.CronJob
extractors/dispatch.ts:
Register the 3 extractors under their resolved aws.* resource types.
Adds the first AWS section to PROPERTY_EXTRACTORS.
Provider parity notes (extractor only — handlers come later):
- ECS multi-port uses the shared parse_exposed_ports() so the canvas
contract matches what Cloud Run sees today.
- Lambda accepts the nested code.{s3Bucket,s3Key} shape AND falls
through to the flat s3_bucket / s3_key fields for back-compat with
the existing Lambda test harness. Auto-build from Source.Repository
lands in commit #28.
- EventBridge cron is the 6-field format (not unix 5-field). The
named "daily"/"hourly"/"weekly"/"monthly" presets that GCP Cloud
Scheduler accepts are normalised to the AWS expression so cards
stay provider-portable.
Tests: 24 new assertions covering defaults, passthrough, exposed_ports
parsing, code-source shape variants, cron preset normalisation. The
dispatch table test gets a new shape — counts GCP entries (27)
separately from AWS (>=3, will grow with commits #3–#6), accepts
aws.* keys in the {provider}.{service}.{kind} regex.
* feat(deploy/aws): extractors for database (rds, dynamodb, elasticache, docdb)
Phase 1 commit 2/5.
extractors/aws/database.ts (new):
- extract_rds_db_instance_properties ← Database.PostgreSQL, MySQL
- extract_dynamodb_table_properties ← Database.DynamoDB
- extract_elasticache_cluster_properties ← Database.Redis
- extract_docdb_cluster_properties ← Database.MongoDB
extractors/dispatch.ts: register all 4 under aws.* resource types.
Provider parity:
- RDS engine + version inferred from iceType + runtime string, same
rule the GCP Cloud SQL extractor uses → cards stay portable.
- master_user_password defaults to '' so the handler fails loudly
rather than provisioning RDS / DocDB with no real credential.
- ElastiCache exposes ELASTICACHE_REDIS_SIZE_MAP for the canvas
M-series enum (M1 → cache.t3.micro, M5 → cache.m5.xlarge ×2 for HA
parity with GCP STANDARD_HA).
- DynamoDB defaults to PAY_PER_REQUEST (AWS-recommended for new
workloads); PROVISIONED branch emits RCU/WCU only when set.
15 new test assertions across the four resources covering engine
detection, version extraction, size-enum translation, billing-mode
branching, and password defaults.
* feat(deploy/aws): extractors for network (s3, apigateway, cloudfront, elbv2)
Phase 1 commit 3/5.
extractors/aws/network.ts (new):
- extract_s3_bucket_properties ← Storage.Bucket / Storage.ObjectStorage / Compute.StaticSite
- extract_api_gateway_rest_api_properties ← Network.Gateway
- extract_cloudfront_distribution_properties ← Network.PublicEndpoint / Network.CustomDomain
- extract_elbv2_load_balancer_properties ← Network.LoadBalancer
extractors/dispatch.ts: register all 4 under aws.* resource types.
Cross-provider parity:
- S3 reads the publicWebsiteSource role from the shared block-
classifier table; same flip-policy the GCP cloud_storage extractor
uses for Compute.StaticSite. Plain Storage.Bucket stays private.
- CloudFront defaults to HTTPS + auto-cert + PriceClass_100 (most-
common cost-aware preset). Cert provisioning in us-east-1 is the
handler's job in commit #19.
- ELBv2 defaults to internet-facing ALB on HTTPS:443; flips to
`internal` scheme when `internal: true` (parity with the
INTERNAL_INGRESS_OVERRIDES table semantics).
11 new tests + dispatch table assertion updated (the previous
"aws.s3.bucket is intentionally absent" assertion is replaced with
a generic "aws.unknown.thing" check now that S3 has landed).
* feat(deploy/aws): extractors for ancillary (sqs, sns, cognito, secrets, cw-logs)
Phase 1 commit 4/5.
extractors/aws/ancillary.ts (new):
- extract_sqs_queue_properties ← Messaging.Queue
- extract_sns_topic_properties ← Messaging.Topic / CloudPubSub
- extract_cognito_user_pool_properties ← Security.Identity
- extract_secrets_manager_secret_properties ← Security.Secret
- extract_cloudwatch_log_group_properties ← Monitoring.Log
extractors/dispatch.ts: register all 5 under aws.* resource types.
Notable:
- SQS content_based_deduplication is only emitted on FIFO queues
(AWS rejects the field on standard SQS).
- Secrets Manager extractor forwards data.secrets as `bindings` —
same shape the schema-declared deploy-expansion pass already uses
for GCP Secret Manager. Adding AWS doesn't require translator
changes; the same expansion branch fires.
- Cognito reads both signInProviders (canvas camelCase) and
sign_in_providers (snake) so projects authored with either work.
14 new test assertions.
* feat(deploy/aws): extractors for AI/analytics (opensearch, bedrock, sagemaker, redshift)
Phase 1 commit 5/5 — last extractor module. Every aws.* resource type
in AWS_TYPE_MAP now has a registered property extractor.
extractors/aws/ai.ts (new):
- extract_opensearch_domain_properties ← AI.VectorDB
- extract_bedrock_endpoint_properties ← AI.LLMGateway
- extract_sagemaker_endpoint_properties ← AI.ModelServing
- extract_redshift_cluster_properties ← Analytics.DataWarehouse
extractors/dispatch.ts: register all 4 under aws.* resource types.
Notable defaults:
- OpenSearch starts cost-conscious: single t3.small.search node with
encryption-at-rest + node-to-node encryption on. Production users
flip dedicated_master_enabled + bump instance_count ≥ 3.
- Bedrock defaults to on-demand Claude 3 Haiku (zero provisioned
model units → handler emits no resource). Provisioned throughput
fires only when model_units > 0.
- SageMaker defaults to a real-time ml.t2.medium endpoint.
- Redshift defaults to a single-node dc2.large with the no-default-
password invariant the RDS + DocDB extractors share.
12 new test assertions. With this commit Phase 1 is complete:
PROPERTY_EXTRACTORS table now has 27 GCP + 20 AWS entries.
* feat(deploy/aws): shared infra — STS account-id resolver + IAM ensure-role helper
Phase 2 commit 1 — the shared helpers later handlers depend on.
providers/aws/account.ts (new):
- create_account_id_resolver(region): memoised STS GetCallerIdentity
caller. First call hits STS, subsequent calls return cached value.
Concurrent first-calls coalesce into one STS request. Throws a
clear "install @aws-sdk/client-sts" message when SDK is absent.
providers/aws/iam-roles.ts (new):
- ensureManagedRole(region, roleName, trustPolicyJson, managedPolicyArn):
idempotent GetRole → CreateRole-on-NoSuchEntity → AttachRolePolicy
pattern. Returns the role ARN. Tolerates already-attached
policies (AlreadyExists swallowed; any other error fatal).
- ensureEcsTaskExecutionRole(region): convenience wrapper for the
standard Fargate execution role (consumed by the ECS handler in
commit #23).
providers/aws/types.ts:
AWSHandlerContext gains `ensure_account_id: AccountIdResolver` —
handlers `await ctx.ensure_account_id()` to get the cached id.
providers/aws/aws-deployer.ts:
initialize() wires the resolver into the context. A pre-init stub
throws "called before initialize()" if a handler tries to use it
out of band.
providers/aws/index.ts: re-export the new helpers.
Tests: 9 new — memoisation, concurrent-call coalescing, missing-SDK
error path, missing-Account-field error path, ensureManagedRole
happy-path + create-on-miss + IAM-SDK-missing path.
* feat(deploy/aws): s3 handler — account-id suffix + publicWebsite bucket policy
Handler #8 in Phase 2.
Two upgrades over the Phase 0 baseline:
1. **Account-id suffix.** S3 bucket names are globally unique
across all AWS accounts. The handler awaits ctx.ensure_account_id()
and appends `-{accountId}` to the translator's resource name
before any SDK call. `ice-myapp-bucket` becomes
`ice-myapp-bucket-111122223333`, eliminating the global-collision
class. The provider_id ARN carries the post-suffix name so
update + delete round-trip cleanly (bucket_name_from_arn parses
it back out).
2. **publicWebsite policy.** When the extractor sets `public_access`
+ `website_hosting` (today only Compute.StaticSite triggers this
via the publicWebsiteSource role from the shared classifier
table), the handler runs a 4-step create:
CreateBucket
→ PutPublicAccessBlock (loosen account-default block)
→ PutBucketPolicy (attach the public-read policy)
→ PutBucketWebsite (set index/404 pages)
Plain Storage.Bucket skips all three follow-up commands.
Tests:
- Existing test harness extended with a makeStsModule mock + a
FAKE_ACCOUNT_ID constant; the makeFullRegistry now installs STS
alongside the SDK clients.
- All existing S3 ARN assertions updated to expect the suffixed form.
- 3 new tests: account-id suffix lock-in, public-website 4-step
sequence with policy + website config, plain-bucket negative path.
64 → 67 AWS deployer tests passing.
* feat(deploy/aws): lambda handler — fail-fast role + code-source validation
Handler #9 in Phase 2.
Hardens the existing Lambda S3-ref handler with two pre-create
validations that turn cryptic AWS API errors into clear messages:
1. **IAM role required.** The AWS SDK returns "Could not find
resource ..." when CreateFunction is called with an empty Role
ARN. The handler now refuses up front with:
"Lambda function requires an IAM execution role ARN
(properties.role). Wire one in or use the auto-role helper."
2. **Code source required.** When neither s3_bucket + s3_key NOR a
base64 zip_file is supplied, the handler refuses with:
"Lambda function code source is missing. Provide
properties.code.{s3Bucket,s3Key} or zip_file (auto-build from
Source.Repository lands in a later commit)."
Both checks fire before any SDK call, so the failure surfaces in the
deployer's `error` field with full context instead of as an opaque
AWS error.
Tests updated so happy-path Lambda create tests now pass both role
and code source. 2 new tests pin the fail-fast paths.
* feat(deploy/aws): cloudwatch-logs handler + shared _result helpers
Handler #10 in Phase 2.
providers/aws/handlers/cloudwatch-logs.ts (new):
- aws.cloudwatch.logGroup handler — CreateLogGroup +
PutRetentionPolicy (when retention_in_days set) on create.
PutRetentionPolicy on update. DeleteLogGroup on delete.
providers/aws/handlers/_result.ts (new):
- ok / err / sdkMissing helpers shared across all AWS handlers.
Stops the per-handler result/fail boilerplate copy-paste.
providers/aws/sdk-loader.ts: load @aws-sdk/client-cloudwatch-logs
under the 'cloudwatch-logs' client key.
providers/aws/aws-deployer.ts: register cloudwatch_logs_handler
in HANDLER_REGISTRY.
Tests: 3 new — create-with-retention, create-without-retention skips
PutRetentionPolicy, delete sequence. Test harness extended with
makeCloudWatchLogsModule + corresponding FakeImportRegistry entry.
* feat(deploy/aws): secrets-manager handler + shared test harness
Handler #11 in Phase 2.
providers/aws/handlers/secrets-manager.ts (new):
- aws.secretsmanager.secret handler. Mirrors the GCP Secret
Manager contract: the schema-declared deploy-expansion pass
emits one Secret per binding row; this handler just creates /
updates / deletes ONE. Values are NOT written (operators
populate via AWS console/CLI — same security tradeoff as GCP).
- delete uses ForceDeleteWithoutRecovery=true (skips the 30-day
recovery window — appropriate when ICE removes the binding).
providers/aws/sdk-loader.ts: load @aws-sdk/client-secrets-manager
under the 'secrets-manager' client key.
providers/aws/aws-deployer.ts: register secrets_manager_handler.
providers/__tests__/_aws-test-harness.ts (new):
Extracts the Function-constructor stub + generic SDK-mock factory
out of the original aws-deployer.test.ts so per-handler test
files stay small. Strips the trailing 'Command' from command
class names when building the __cmd label so assertions read the
operation name (`CreateSecret`, not `CreateSecretCommand`).
providers/__tests__/aws-secrets-manager.test.ts (new): 4 focused
tests — create returns the SDK ARN, update + delete sequences,
SDK-not-installed path.
* feat(deploy/aws): sqs handler — CreateQueue/SetQueueAttributes/DeleteQueue, FIFO .fifo suffix
Handler #12 in Phase 2. Standard + FIFO queues. FIFO queues get the
.fifo suffix appended to the name automatically (AWS enforces). 3
focused tests.
* feat(deploy/aws): sns handler — CreateTopic/SetTopicAttributes/DeleteTopic, FIFO .fifo suffix
* feat(deploy/aws): dynamodb handler — CreateTable + key schema + PITR
* feat(deploy/aws): elasticache handler — single-node + replication-group paths
* feat(deploy/aws): rds handler — no-default-password gate + provisioning poll
Handler #16 in Phase 2. CreateDBInstance + 20-min status-poll loop
that respects ctx.abort_signal and reports progress via on_step.
Refuses to create when master_user_password is empty (parity with
the extractor's no-default-password invariant).
* feat(deploy/aws): docdb handler — cluster + per-instance creation
* feat(deploy/aws): cognito handler — user pool with password policy + MFA
* feat(deploy/aws): cloudfront handler — us-east-1 ACM cert + minimal distribution
Handler #19. CloudFront requires ACM certs in us-east-1 regardless
of deploy region; the handler spins up a one-shot ACM client pinned
to us-east-1 for RequestCertificate, then attaches the ARN to the
distribution's ViewerCertificate. Falls back to CloudFrontDefaultCertificate
when ACM SDK is absent.
* feat(deploy/aws): elbv2 handler — LB + skeleton target group
* feat(deploy/aws): api-gateway handler — REST API + default-stage deployment
* feat(deploy/aws): events-rule handler (CronJob) — PutRule + PutTargets
* feat(deploy/aws): ecs handler — auto-cluster + task role + service create
Handler #23. Compute.Container 'just works' on AWS — the handler
idempotently bootstraps ecsTaskExecutionRole + ice-default-cluster
before RegisterTaskDefinition + CreateService. Mirrors the GCP
Cloud Run UX (no cluster to think about).
* feat(deploy/aws): opensearch handler — CreateDomain with cluster/EBS/encryption config
* feat(deploy/aws): bedrock handler — on-demand no-op + provisioned-throughput create
* feat(deploy/aws): sagemaker handler — EndpointConfig + Endpoint, requires model_name
* feat(deploy/aws): redshift handler — CreateCluster + no-default-password gate
* feat(deploy/aws): lambda auto-build from Source.Repository
Phase 3 (commit #28). When a Compute.ServerlessFunction block has a
connected Source.Repository AND no explicit S3 ref, the handler
auto-builds the zip and uploads it before CreateFunction:
1. git clone --depth 1 --branch <branch> <repo>
2. npm install --omit=dev (skipped if no package.json)
3. zip -qr function.zip .
4. PutObject to ice-bootstrap-{accountId}-{region}/lambda/{name}/{ts}.zip
(HeadBucket → CreateBucket if absent)
5. Stamp s3_bucket + s3_key onto properties and continue.
Local-only — assumes git/npm/zip on the deploy host. AWS CodeBuild
integration deferred to a future commit. Existing manual S3-ref + zip
paths are unchanged; the auto-build branch only fires when
`properties.repository` is set AND no explicit code source exists.
* test(deploy/aws): unskip AWS Type Map block + end-to-end coverage
Phase 4 commit #29. With every aws.* resource type registered in
PROPERTY_EXTRACTORS (commits #2–#6), the AWS Type Map test block can
finally turn on. Expanded the iceType matrix from 5 to 19 entries
covering every AWS-mapped block.
New end-to-end test wires Compute.StaticSite + Security.Secret (with
two bindings — exercising the schema-declared deploy-expansion pass)
+ Database.PostgreSQL into a single translator call, asserts the
resulting graph has 4 deployables resolving to s3.bucket /
secretsmanager.secret×2 / rds.dbInstance. The Azure block remains
skipped (deferred to a future Azure handler buildout).
* docs(deploy/aws): provider notes — quirks, assumptions, deferred work
Phase 4 commit #30 — final commit of the AWS buildout.
providers/aws/README.md documents the AWS-specific decisions the 30
commits in this series bake in:
- architecture (mirrors gcp/, schema-driven HANDLER_REGISTRY)
- S3 account-id suffix
- CloudFront us-east-1 cert
- ECS auto-cluster + task role
- RDS / DocDB / Redshift no-default-password invariant
- RDS provisioning poll
- Lambda auto-build flow (git + npm + zip + bootstrap S3)
- Bedrock on-demand no-op
- Secrets Manager values-never-written contract
- SQS / SNS .fifo suffix
- SDK packages as optional peer deps
- test harness layout
- deferred work (VPC blocks, CodeBuild, drift detection, LocalStack)
Read this before changing any AWS handler.
* feat(aws): selectively enable safe categories via feature flags
Flip PROVIDER_FLAGS.aws.enabled to true with a hand-picked category
map (Storage, Messaging, Cache, Monitoring, Security, Source, Config).
Compute / Frontend / Scheduler / Network / Database / AI / Analytics
stay gated until their concrete unblockers land — ECS VPC blocks,
CloudFront cert-validation flow, update-paths, etc.
README.md gets a Rollout state table documenting why each gated
category is held back and what unblocks it.
Integrity test in packages/constants asserts the per-category map
stays exhaustive, so future CategoryId additions force a deliberate
on/off decision here.
* fix(palette): enable provider dropdown items when any block is available
Replace the project-provider lock on the palette provider dropdown
with an availability check: a provider option is selectable iff at
least one concept has it in providers and its category is enabled
for that provider.
Before: in a GCP project, AWS was greyed in the palette dropdown
even after AWS feature-flag enabled — so users couldn't browse the
AWS catalog from a GCP project.
After: AWS opens as long as it has any available block under the
current PROVIDER_FLAGS — drag-into-project compatibility remains
enforced at the canvas-drop layer.
availableProviderIds is derived in resource-palette.tsx from the
unfiltered component list using isCategoryEnabledForProvider — same
schema-driven gate the component filter already uses.
* docs(architecture): explain how canvas edges become cloud infra
New page docs/architecture/connections-to-cloud.md walks the five-layer
pipeline (connection-rules → propagation → type-maps → extractors →
handlers) and grounds it with two worked GCP examples:
- Storage.Bucket → Compute.BackendAPI: env-var injection + IAM binding,
no edge resource in GCP.
- Compute.CronJob → Compute.BackendAPI: Cloud Scheduler HTTP target +
run.invoker IAM binding.
Links the new page from architecture/README.md and the existing
core-engine.md "Computing flows" section so readers landing on either
find their way to the deep dive.
* fix(typecheck): unblock blocks + templates + core deploy-expansion
- deploy-expansion: use get_node_by_name for name-based dedup; has_node
expects a branded NodeId, not a plain string.
- requirements.test: vitest needs `beforeEach` in the named imports
(was previously globalised but tsc no longer sees it).
- validate.test: annotate `.map((c) => ...)` callbacks; vitest's bare
`ReturnType<typeof vi.spyOn>` no longer carries the called-fn signature
so the implicit-any error fires.
* fix(typecheck): unblock packages/ui + packages/web
Sweep the workspace's pre-existing typecheck errors so the whole repo
compiles cleanly under tsc --noEmit:
- packages/constants: re-export IntegrationStatus from the barrel so
packages/ui/src/store/slices/integrations-slice.ts resolves.
- vitest type tightening: `vi.fn(() => ...)` infers Parameters as [],
breaking `.mock.calls[i][j]` indexing. Widen to (..._args: unknown[])
on the mock decls that get indexed (deploy-panel, requirements-
section, deploy-diagnosis, inline-table-view, axios-instance,
use-cost-calculation, use-computing-flows, template-picker,
invite-accept).
- stopPropagation event mocks: vitest no longer accepts
`{ stopPropagation: vi.fn() } as React.MouseEvent` without an unknown
intermediate. Sweep through compact-node / custom-domain / group-node
/ log-node / palette / inline-table tests.
- KNOWN_MOCKS includes: cast through unknown[] in canvas-context-menu
and inline-table-view test helpers.
- block-summary-card: import CanvasNode from ../../../svg-canvas (the
path resolved one level too shallow).
- blueprints test: import BlockBlueprint from ../types not ../../types.
- group-node + region-label test fixtures: type 'container' (the
CanvasNode union doesn't include 'group' or 'region' yet).
- reroute-node: switch sockets prop from SocketDef[] to PortDef[] with
role: 'any' to match TypedSockets' contract.
- use-wizard-state: add missing 'name' field on EnvironmentPreset
fixture.
- store/index.test: cast resolveFirst to its original closure type so
optional-call type-narrows correctly.
- use-mouse-handlers test: drop minZoom/maxZoom (not in
UseMouseHandlersDeps).
- deploy-diagnosis: widen the diagnosis state shape; replace
setImmediate with setTimeout(resolve, 0) — Node's setImmediate isn't
surfaced in the test types.
* docs(architecture): explain how canvas edges become cloud infra
* docs(readme): link AWS rollout state + connections-to-cloud page
- root README: sharpen "AWS — in progress" to mention the handler /
extractor count and link the staged-rollout table in the AWS README.
- docs/README: add connections-to-cloud to the architecture mermaid
and to the contributors table.
* docs(aws): reflect handler buildout + staged rollout
- provider-status: AWS matrix entry now lists the 17 handlers + 20
extractors and the per-category feature-flag state instead of the
stale "EC2 / S3 / Lambda only" copy.
- deploying-to-aws: drop the dead reference to "provider-status.md - to
be added" (the doc exists now), fix the broken handlers-source link
(handlers live at packages/core/src/deploy/providers/aws/, not
packages/providers/aws/), fix the broken architecture.md anchor.
- Add a quirks section pointing operators at the AWS README for S3
account-id suffix, CloudFront us-east-1 cert pin, ECS auto-cluster,
RDS password gate + provisioning poll, Lambda auto-build, FIFO
suffix. Update the "known gaps" list to match the deferred items in
the AWS README (VPC blocks, CodeBuild, update paths, LocalStack).
Bumps the vitest group with 1 update in the / directory: [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest). Updates `vitest` from 4.1.0 to 4.1.7 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.7/packages/vitest) --- updated-dependencies: - dependency-name: vitest dependency-version: 4.1.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vitest ... Signed-off-by: dependabot[bot] <support@github.com>
c090ce5 to
78154b4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps the vitest group with 1 update in the / directory: vitest.
Updates
vitestfrom 4.1.0 to 4.1.7Release notes
Sourced from vitest's releases.
... (truncated)
Commits
a09d472chore: release v4.1.7a8fd24cchore: release v4.1.618af98cfix(browser): simplify orchestrator otel carrier (#10285)3188260feat(browser): provide project reference inToMatchScreenshotResolvePath(#...e399846chore: release v4.1.57dc6d54Revert "fix: respect diff config options in soft assertions (#8696)"9787dedfix: respect diff config options in soft assertions (#8696)325463afix(ast-collect): recognize _vi_import prefix in static test discovery (#10...0e0ff41feat(coverage): istanbul to supportinstrumenteroption (#10119)663b99ffix: aliasagentreporter tominimal(#10157)