@ampless/backend 1.0.0-alpha.45 → 1.0.0-alpha.46
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/dist/events/processor-trusted.js +29 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +41 -0
- package/package.json +3 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/events/processor-trusted.ts
|
|
2
2
|
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
3
|
-
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
3
|
+
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
|
|
4
|
+
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
4
5
|
import {
|
|
5
6
|
DynamoDBDocumentClient,
|
|
6
7
|
DeleteCommand,
|
|
@@ -85,7 +86,9 @@ function createProcessorTrustedHandler(opts) {
|
|
|
85
86
|
const POST_TABLE = requireEnv("AMPLESS_POST_TABLE");
|
|
86
87
|
const KV_TABLE = requireEnv("AMPLESS_KV_TABLE");
|
|
87
88
|
const POSTTAG_TABLE = requireEnv("AMPLESS_POSTTAG_TABLE");
|
|
89
|
+
const PLUGIN_SECRET_TABLE = requireEnv("AMPLESS_PLUGIN_SECRET_TABLE");
|
|
88
90
|
const REGION = requireEnv("AWS_REGION");
|
|
91
|
+
const rawDdb = new DynamoDBClient({});
|
|
89
92
|
async function listPublished() {
|
|
90
93
|
const items = [];
|
|
91
94
|
let exclusiveStartKey;
|
|
@@ -121,6 +124,7 @@ function createProcessorTrustedHandler(opts) {
|
|
|
121
124
|
function makeContext(plugin) {
|
|
122
125
|
const namespace = plugin.instanceId ?? plugin.name;
|
|
123
126
|
const label = plugin.instanceId ? `${plugin.name}#${plugin.instanceId}` : plugin.name;
|
|
127
|
+
const secretCache = /* @__PURE__ */ new Map();
|
|
124
128
|
return {
|
|
125
129
|
site: opts.site,
|
|
126
130
|
listPublishedPosts: () => listPublished(),
|
|
@@ -146,6 +150,30 @@ function createProcessorTrustedHandler(opts) {
|
|
|
146
150
|
})
|
|
147
151
|
);
|
|
148
152
|
return formatPublicAssetUrl(BUCKET, REGION, objectKey);
|
|
153
|
+
},
|
|
154
|
+
async secret(key) {
|
|
155
|
+
const cacheKey = `${namespace}:${key}`;
|
|
156
|
+
if (secretCache.has(cacheKey)) {
|
|
157
|
+
return secretCache.get(cacheKey);
|
|
158
|
+
}
|
|
159
|
+
const sk = `plugins.${namespace}.${key}`;
|
|
160
|
+
try {
|
|
161
|
+
const result = await rawDdb.send(
|
|
162
|
+
new GetItemCommand({
|
|
163
|
+
TableName: PLUGIN_SECRET_TABLE,
|
|
164
|
+
Key: marshall({ siteId: "default", sk })
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
const value = result.Item ? unmarshall(result.Item).value : void 0;
|
|
168
|
+
secretCache.set(cacheKey, value);
|
|
169
|
+
return value;
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error(
|
|
172
|
+
`[trusted-processor] ${label}: ctx.secret("${key}") DDB read failed`,
|
|
173
|
+
err
|
|
174
|
+
);
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
149
177
|
}
|
|
150
178
|
};
|
|
151
179
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -396,6 +396,47 @@ function amplessSchemaModels(a, opts = {}) {
|
|
|
396
396
|
}).identifier(["hash"]).authorization((allow) => [
|
|
397
397
|
allow.groups(["ampless-admin"])
|
|
398
398
|
]),
|
|
399
|
+
// Isolated secret storage for trusted plugins (Phase 6a).
|
|
400
|
+
//
|
|
401
|
+
// This is a COMPLETELY SEPARATE model from KvStore. KvStore grants
|
|
402
|
+
// admin/editor full read access through AppSync, which means any
|
|
403
|
+
// value stored there can be read by anyone with admin/editor
|
|
404
|
+
// credentials. PluginSecret has NO read authorization for any
|
|
405
|
+
// Cognito group — read is exclusively granted to IAM-authenticated
|
|
406
|
+
// principals (i.e. the trusted-processor Lambda role).
|
|
407
|
+
//
|
|
408
|
+
// Authorization design:
|
|
409
|
+
// - admin / editor: CREATE, UPDATE, DELETE only. The AppSync
|
|
410
|
+
// schema will not generate getPluginSecret / listPluginSecrets
|
|
411
|
+
// queries for these groups because 'read' is absent.
|
|
412
|
+
// - IAM (Lambda): read only. The trusted-processor Lambda uses
|
|
413
|
+
// DDB SDK GetItem directly (not AppSync) to read secrets.
|
|
414
|
+
//
|
|
415
|
+
// Storage key convention:
|
|
416
|
+
// siteId = 'default' (single-site architecture)
|
|
417
|
+
// sk = `plugins.${instanceId ?? name}.${fieldKey}`
|
|
418
|
+
//
|
|
419
|
+
// DynamoDB auto-encrypts at rest (AWS-managed KMS key). Secrets
|
|
420
|
+
// never flow to the S3 site-settings mirror because the trusted
|
|
421
|
+
// processor only queries KvStore (pk='siteconfig') for that path —
|
|
422
|
+
// PluginSecret is a structurally separate table.
|
|
423
|
+
PluginSecret: a.model({
|
|
424
|
+
// Single-site architecture: siteId is always 'default'.
|
|
425
|
+
siteId: a.string().required(),
|
|
426
|
+
// Composite sort key: `plugins.<instanceId>.<fieldKey>`
|
|
427
|
+
sk: a.string().required(),
|
|
428
|
+
// The secret value (plaintext string). DynamoDB's server-side
|
|
429
|
+
// encryption (SSE) with AWS-owned KMS protects the value at
|
|
430
|
+
// rest. IAM controls Lambda read; AppSync controls admin write.
|
|
431
|
+
value: a.string().required()
|
|
432
|
+
}).identifier(["siteId", "sk"]).authorization((allow) => [
|
|
433
|
+
// admin/editor can create/update/delete but NOT read.
|
|
434
|
+
// 'read' is intentionally omitted so AppSync does not generate
|
|
435
|
+
// getPluginSecret / listPluginSecrets queries for these groups.
|
|
436
|
+
allow.groups(["ampless-admin", "ampless-editor"]).to(["create", "update", "delete"]),
|
|
437
|
+
// Trusted Lambda reads via IAM-signed requests (SigV4).
|
|
438
|
+
allow.authenticated("iam").to(["read"])
|
|
439
|
+
]),
|
|
399
440
|
// Custom return type for public post reads. Decoupling from `Post` lets
|
|
400
441
|
// AppSync skip the model-level (admin-only) auth check on fields.
|
|
401
442
|
//
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampless/backend",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.46",
|
|
4
4
|
"description": "Amplify Gen 2 backend factories for ampless: auth, data, storage, event processors, API key renewer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"@smithy/protocol-http": "^5.4.4",
|
|
66
66
|
"@smithy/signature-v4": "^5.4.4",
|
|
67
67
|
"fflate": "^0.8.3",
|
|
68
|
-
"ampless": "1.0.0-alpha.
|
|
69
|
-
"@ampless/mcp-server": "1.0.0-alpha.
|
|
68
|
+
"ampless": "1.0.0-alpha.29",
|
|
69
|
+
"@ampless/mcp-server": "1.0.0-alpha.35"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"@aws-amplify/backend": "^1",
|