@anthusai/papyrus 2.0.0-next.6 → 2.0.0-next.7

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.
@@ -4,7 +4,10 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Any
6
6
 
7
- from papyrus_content.editorial_checks import GraphQLEditorialStore, Services, handle
7
+ from papyrus_content.editorial_checks import GraphQLEditorialStore, Services, handle, load_provider_keys
8
+
9
+ # Amplify passes secrets to Python functions as placeholders; resolve them once per cold start.
10
+ load_provider_keys()
8
11
 
9
12
 
10
13
  def handler(event: dict[str, Any], _context: Any = None) -> dict[str, Any]:
@@ -13,6 +13,20 @@ export const EDITORIAL_CHECKS_FUNCTION_FIELDS = [
13
13
  "Mutation/fields/createEditorialPolicy",
14
14
  "Mutation/fields/updateEditorialPolicy",
15
15
  ];
16
+ export const EDITORIAL_CHECKS_SECRETS = ["TYPESAFE_API_KEY", "OPENAI_API_KEY"];
17
+ /**
18
+ * SSM parameters holding the provider keys. A Python function reads its secret()
19
+ * values itself (Amplify only resolves them for Node functions), so it needs read
20
+ * access to the app's branch and shared secret paths, and to the sandbox paths.
21
+ */
22
+ export function editorialChecksSecretParameters(region, account, appId) {
23
+ const arn = (path) => `arn:aws:ssm:${region}:${account}:parameter/amplify/${path}`;
24
+ return EDITORIAL_CHECKS_SECRETS.flatMap((name) => [
25
+ arn(`papyrus/*/${name}`),
26
+ arn(`shared/papyrus/${name}`),
27
+ ...(appId ? [arn(`${appId}/*/${name}`), arn(`shared/${appId}/${name}`)] : []),
28
+ ]);
29
+ }
16
30
  export const editorialChecksManifest = {
17
31
  name: "editorial-checks",
18
32
  contract: 1,
@@ -39,8 +53,13 @@ export const editorialChecksPlugin = {
39
53
  const lambda = backend.editorialChecks.resources.lambda;
40
54
  const stack = Stack.of(lambda);
41
55
  lambda.addEnvironment("PAPYRUS_GRAPHQL_ENDPOINT", context.graphqlEndpoint);
42
- backend.editorialChecks.addEnvironment("TYPESAFE_API_KEY", secret("TYPESAFE_API_KEY"));
43
- backend.editorialChecks.addEnvironment("OPENAI_API_KEY", secret("OPENAI_API_KEY"));
56
+ for (const name of EDITORIAL_CHECKS_SECRETS)
57
+ backend.editorialChecks.addEnvironment(name, secret(name));
58
+ lambda.addToRolePolicy(new PolicyStatement({
59
+ effect: Effect.ALLOW,
60
+ actions: ["ssm:GetParameter", "ssm:GetParameters"],
61
+ resources: editorialChecksSecretParameters(stack.region, stack.account, (process.env.AWS_APP_ID ?? "").trim()),
62
+ }));
44
63
  lambda.addToRolePolicy(new PolicyStatement({
45
64
  effect: Effect.ALLOW,
46
65
  actions: ["appsync:GraphQL"],
@@ -21,6 +21,22 @@ export const EDITORIAL_CHECKS_FUNCTION_FIELDS = [
21
21
  "Mutation/fields/updateEditorialPolicy",
22
22
  ];
23
23
 
24
+ export const EDITORIAL_CHECKS_SECRETS = ["TYPESAFE_API_KEY", "OPENAI_API_KEY"];
25
+
26
+ /**
27
+ * SSM parameters holding the provider keys. A Python function reads its secret()
28
+ * values itself (Amplify only resolves them for Node functions), so it needs read
29
+ * access to the app's branch and shared secret paths, and to the sandbox paths.
30
+ */
31
+ export function editorialChecksSecretParameters(region: string, account: string, appId: string): string[] {
32
+ const arn = (path: string) => `arn:aws:ssm:${region}:${account}:parameter/amplify/${path}`;
33
+ return EDITORIAL_CHECKS_SECRETS.flatMap((name) => [
34
+ arn(`papyrus/*/${name}`),
35
+ arn(`shared/papyrus/${name}`),
36
+ ...(appId ? [arn(`${appId}/*/${name}`), arn(`shared/${appId}/${name}`)] : []),
37
+ ]);
38
+ }
39
+
24
40
  export const editorialChecksManifest: PluginManifest = {
25
41
  name: "editorial-checks",
26
42
  contract: 1,
@@ -48,8 +64,14 @@ export const editorialChecksPlugin: PapyrusPlugin<EditorialChecksPluginConfig, {
48
64
  const lambda = backend.editorialChecks.resources.lambda as LambdaFunction;
49
65
  const stack = Stack.of(lambda);
50
66
  lambda.addEnvironment("PAPYRUS_GRAPHQL_ENDPOINT", context.graphqlEndpoint);
51
- backend.editorialChecks.addEnvironment("TYPESAFE_API_KEY", secret("TYPESAFE_API_KEY"));
52
- backend.editorialChecks.addEnvironment("OPENAI_API_KEY", secret("OPENAI_API_KEY"));
67
+ for (const name of EDITORIAL_CHECKS_SECRETS) backend.editorialChecks.addEnvironment(name, secret(name));
68
+ lambda.addToRolePolicy(
69
+ new PolicyStatement({
70
+ effect: Effect.ALLOW,
71
+ actions: ["ssm:GetParameter", "ssm:GetParameters"],
72
+ resources: editorialChecksSecretParameters(stack.region, stack.account, (process.env.AWS_APP_ID ?? "").trim()),
73
+ }),
74
+ );
53
75
  lambda.addToRolePolicy(
54
76
  new PolicyStatement({
55
77
  effect: Effect.ALLOW,
package/package.json CHANGED
@@ -395,7 +395,7 @@
395
395
  "optional": true
396
396
  }
397
397
  },
398
- "version": "2.0.0-next.6",
398
+ "version": "2.0.0-next.7",
399
399
  "dependencies": {
400
400
  "@aws-amplify/adapter-nextjs": "^1.7.3",
401
401
  "@aws-crypto/sha256-js": "5.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.0-next.6",
2
+ "version": "2.0.0-next.7",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",