@aws-blocks/bb-app-setting 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +78 -0
- package/README.md +2 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +12 -3
- package/src/version.ts +1 -1
package/DESIGN.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# AppSetting — Design
|
|
2
|
+
|
|
3
|
+
**Package:** `@aws-blocks/bb-app-setting`
|
|
4
|
+
**Type:** Primitive (new infrastructure)
|
|
5
|
+
**AWS Service:** SSM Parameter Store (String + SecureString)
|
|
6
|
+
|
|
7
|
+
## Infrastructure (CDK)
|
|
8
|
+
|
|
9
|
+
### String Parameters (`secret` not set or `false`)
|
|
10
|
+
|
|
11
|
+
Creates one `aws-cdk-lib/aws-ssm.StringParameter` per AppSetting instance:
|
|
12
|
+
|
|
13
|
+
- **Parameter name:** Taken from `options.name`
|
|
14
|
+
- **Parameter type:** String (standard tier, 4 KB limit, free)
|
|
15
|
+
- **Initial value:** Serialized form of `options.value` (JSON string for objects, raw string for strings)
|
|
16
|
+
- **Removal policy:** DESTROY (parameter cleaned up on stack deletion)
|
|
17
|
+
- **Permissions granted to `this.handler`:**
|
|
18
|
+
- `ssm:GetParameter` on the parameter ARN
|
|
19
|
+
- `ssm:PutParameter` on the parameter ARN
|
|
20
|
+
- **Environment variable:** SSM parameter name passed to the Lambda handler via `BLOCKS_SSM_PARAM_{ID}` so the AWS runtime can discover the parameter
|
|
21
|
+
|
|
22
|
+
### SecureString Parameters (`secret: true`)
|
|
23
|
+
|
|
24
|
+
CloudFormation cannot natively create SSM SecureString parameters. The CDK implementation uses a Custom Resource Lambda to create and manage the parameter:
|
|
25
|
+
|
|
26
|
+
- **Custom Resource Lambda:**
|
|
27
|
+
- Uses `lambda.Code.fromInline()` with `@aws-sdk/client-ssm` and `crypto`
|
|
28
|
+
- On `Create`: generates a **random** secret via `crypto.randomBytes(32).toString('base64url')` and calls `PutParameterCommand` with `Type: 'SecureString'`, `Overwrite: false` (no serialized initial value — secrets never come from source)
|
|
29
|
+
- On `Delete`: calls `DeleteParameterCommand` to clean up the parameter
|
|
30
|
+
- On `Update`: generates a random secret for newly added names (same as `Create`) **and** deletes parameters for names removed since the previous deployment (not a no-op); existing values are left untouched and managed at runtime via `put()`
|
|
31
|
+
- Granted `ssm:PutParameter` and `ssm:DeleteParameter` scoped to the parameter ARN, plus `kms:Encrypt` (with the `kms:ViaService` condition) so it can write the encrypted SecureString
|
|
32
|
+
- A single shared Lambda + `CustomResource` is created per stack; each secret parameter name is appended to the resource's `ParameterNames` list
|
|
33
|
+
|
|
34
|
+
- **KMS encryption:** Uses the default `aws/ssm` managed KMS key (no custom key needed, $0/month)
|
|
35
|
+
|
|
36
|
+
- **Handler permissions (the runtime `this.handler`):**
|
|
37
|
+
- `ssm:GetParameter` on the parameter ARN
|
|
38
|
+
- `ssm:PutParameter` on the parameter ARN
|
|
39
|
+
- `kms:Decrypt` **and** `kms:Encrypt` with a `kms:ViaService` condition restricting usage to `ssm.{region}.amazonaws.com`
|
|
40
|
+
|
|
41
|
+
## Serialization & Validation
|
|
42
|
+
|
|
43
|
+
Values are always serialized with `JSON.stringify()` on write and deserialized with `JSON.parse()` on read, regardless of type. This ensures consistent round-tripping for all value types (strings, numbers, booleans, objects). Both the AWS runtime (SSM parameter) and the mock (disk file) store the same JSON-encoded string.
|
|
44
|
+
|
|
45
|
+
The table below shows the AWS runtime (SSM) representation:
|
|
46
|
+
|
|
47
|
+
| Operation | Behavior |
|
|
48
|
+
|-----------|----------|
|
|
49
|
+
| `put()` store | `JSON.stringify(value)` |
|
|
50
|
+
| `get()` retrieve | `JSON.parse(stored)` with fallback to raw value |
|
|
51
|
+
|
|
52
|
+
**Tolerant reader:** `get()` wraps `JSON.parse()` in a try/catch. If parsing fails, the raw value is returned as-is. This fallback is load-bearing in two cases: (1) the CDK secret Lambda writes generated secrets as raw base64url strings (never JSON-stringified), and (2) legacy values written by older versions without `JSON.stringify`. Note: legacy values that happen to be valid JSON (e.g. `"123"`, `"true"`) will be parsed to their JSON type (number, boolean) — not returned as strings. All values written by `put()` going forward will round-trip correctly.
|
|
53
|
+
|
|
54
|
+
When `options.schema` is provided (any `StandardSchemaV1` implementation — Zod, Valibot, ArkType, etc.), the type parameter `T` is inferred from the schema and every `put()` validates the value at runtime before writing. Validation failures throw with `error.name = 'ValidationFailedException'`. When no schema is provided, `T` defaults to `string` with no runtime validation.
|
|
55
|
+
|
|
56
|
+
The 4 KB (4096 bytes) size limit applies to the **JSON-encoded** value of non-secret parameters, matching the SSM standard tier. Because `JSON.stringify()` adds overhead (e.g. 2 bytes for string quotes, escaping for special characters), the effective payload capacity is slightly less than 4096 bytes of raw content. The mock enforces this by checking `Buffer.byteLength(serialized, 'utf8')` only when `!isSecret`. Secret (`SecureString`) parameters are auto-generated rather than taking a user-supplied value, so the mock does not size-check them.
|
|
57
|
+
|
|
58
|
+
## Mock Implementation
|
|
59
|
+
|
|
60
|
+
- Data stored in `.bb-data/settings/{scope.fullId}/value.json`.
|
|
61
|
+
- Data persists across dev server restarts. Customers can wipe with `rm -rf .bb-data`.
|
|
62
|
+
- `get()` returns the stored value from disk, or the initial `value` from constructor if no file exists.
|
|
63
|
+
- `put()` writes the value to disk immediately.
|
|
64
|
+
- Schema validation on `put()` when configured, throws `ValidationFailedException`.
|
|
65
|
+
- Validates 4 KB serialized value size limit for non-secret parameters.
|
|
66
|
+
- `secret: true` behaves identically to non-secret (no encryption locally).
|
|
67
|
+
|
|
68
|
+
### Mock vs AWS Behavior Differences
|
|
69
|
+
|
|
70
|
+
| Behavior Difference | Impact | Mitigation |
|
|
71
|
+
|------------|--------|------------|
|
|
72
|
+
| No KMS encryption for secrets | Secret values stored in plaintext on disk | Acceptable for local dev — real credentials should not be used in mock mode. Document the gap. |
|
|
73
|
+
| No SSM parameter versioning | Local overwrites are not versioned | No mitigation — versioning is not exposed in the API surface |
|
|
74
|
+
| No throughput limits (40 TPS for GetParameter) | Code that would be throttled in AWS succeeds locally | Document the gap; recommend sandbox testing for throughput-sensitive flows |
|
|
75
|
+
| Immediate consistency | Reads always reflect the latest write locally | No mitigation — SSM same-region reads are strongly consistent for GetParameter, so this is actually close to parity |
|
|
76
|
+
| No IAM enforcement | Permission errors only surface in AWS | No mitigation at mock level — IAM is handled by CDK grants automatically |
|
|
77
|
+
| Disk I/O vs SSM latency | Local ops are faster and never timeout | No mitigation needed — latency differences don't affect correctness |
|
|
78
|
+
| No parameter policies / expiration | Settings never expire locally | No mitigation — parameter policies are an advanced SSM feature outside scope |
|
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ A single application configuration value backed by SSM Parameter Store.
|
|
|
6
6
|
|
|
7
7
|
**When NOT to use:** If you need structured key-value data with conditional writes and queries, use `KVStore` or `DistributedTable`.
|
|
8
8
|
|
|
9
|
+
> Design & mock parity details: [DESIGN.md](./DESIGN.md)
|
|
10
|
+
|
|
9
11
|
## API
|
|
10
12
|
|
|
11
13
|
```typescript
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-blocks/bb-app-setting",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/aws-devtools-labs/aws-blocks.git",
|
|
7
|
+
"directory": "packages/bb-app-setting"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/aws-devtools-labs/aws-blocks/tree/main/packages/bb-app-setting#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/aws-devtools-labs/aws-blocks/issues"
|
|
12
|
+
},
|
|
4
13
|
"author": "Amazon Web Services",
|
|
5
14
|
"license": "Apache-2.0",
|
|
6
15
|
"type": "module",
|
|
@@ -30,8 +39,8 @@
|
|
|
30
39
|
"test": "node --test --test-concurrency=1 dist/**/*.test.js"
|
|
31
40
|
},
|
|
32
41
|
"dependencies": {
|
|
33
|
-
"@aws-blocks/core": "^0.
|
|
34
|
-
"@aws-blocks/bb-logger": "^0.1.
|
|
42
|
+
"@aws-blocks/core": "^0.2.0",
|
|
43
|
+
"@aws-blocks/bb-logger": "^0.1.4",
|
|
35
44
|
"@aws-sdk/client-ssm": "^3.0.0",
|
|
36
45
|
"@standard-schema/spec": "^1.1.0"
|
|
37
46
|
},
|
package/src/version.ts
CHANGED