@anvil-cloud/sdk 0.0.8 → 0.0.10

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/README.md CHANGED
@@ -4,69 +4,80 @@
4
4
 
5
5
  Anvil wraps raw cloud resources into opinionated, production-ready components. No 200-line Terraform modules. No copy-pasting security configs. Just declare what you need and Anvil handles the rest.
6
6
 
7
+ Built on [Pulumi](https://www.pulumi.com/).
8
+
7
9
  ## Install
8
10
 
9
11
  ```bash
10
12
  npm install @anvil-cloud/sdk
11
13
  ```
12
14
 
13
- ## Quick start
15
+ ## Secure by default
14
16
 
15
- Create `anvil.config.ts` at your project root:
17
+ Every Anvil component ships with defaults aligned to production from day one — public access blocked, encryption enforced, cost tags applied. The goal isn't to make compliance automatic, but to make it a platform you can actually build on.
16
18
 
17
- ```typescript
18
- import { App } from '@anvil-cloud/sdk';
19
- import * as anvil from '@anvil-cloud/sdk';
19
+ ## The App class
20
+
21
+ Every Anvil program starts with `new App()`. The `run` callback receives a `Context` with:
22
+
23
+ - `ctx.stage` — current deployment stage (defaults to your OS username for dev isolation)
24
+ - `ctx.project` — project name from `anvil.yaml`
25
+ - `ctx.export(name, value)` — export stack outputs
26
+ - `ctx.providers` — named cloud providers for multi-region / multi-account
27
+
28
+ ## Grants
29
+
30
+ Grants are how Anvil wires permissions between resources. Instead of writing IAM policies by hand, you call `.grant()` on a resource and Anvil handles both the IAM role policy and the environment variable injection automatically.
31
+
32
+ A Lambda reading from a Bucket:
20
33
 
34
+ ```typescript
21
35
  export default new App({
22
36
  run(ctx) {
23
37
  const bucket = new anvil.aws.Bucket('uploads', {
24
38
  dataClassification: 'sensitive',
25
39
  });
26
- ctx.export('bucketName', bucket.bucketName);
27
- },
28
- });
29
- ```
30
40
 
31
- Deploy:
41
+ const fn = new anvil.aws.Lambda('processor', {
42
+ runtime: 'nodejs20.x',
43
+ handler: 'index.handler',
44
+ code: './src',
45
+ });
32
46
 
33
- ```bash
34
- anvil deploy
47
+ // Grants the Lambda read access to the bucket and scopes down to specific bucket paths
48
+ // Anvil creates the IAM policy and injects UPLOADS_BUCKET_NAME
49
+ // into the Lambda's environment automatically.
50
+ //
51
+ bucket.grant(fn, { actions: ['read'], path: ['user/*'] });
52
+ },
53
+ });
35
54
  ```
36
55
 
37
- That S3 bucket ships with public access blocked, encryption enabled, and versioning on — because that's how every bucket should start. You opt _in_ to risk, not out of it.
38
-
39
- ## The App class
56
+ What Anvil does under the hood:
40
57
 
41
- Every Anvil program starts with `new App()`. The `run` callback receives a `Context` with:
58
+ - Creates an IAM `RolePolicy` scoped to the exact actions requested
59
+ - Injects the resource identifier as an environment variable on the target (e.g. `UPLOADS_BUCKET_NAME`)
60
+ - No manual ARN wiring, no forgotten permissions
42
61
 
43
- - `ctx.stage` — the current deployment stage (defaults to your OS username for dev isolation)
44
- - `ctx.project` — the project name from `anvil.yaml`
45
- - `ctx.export(name, value)` — export stack outputs
46
- - `ctx.providers` — named cloud providers for multi-region / multi-account
62
+ ## SvelteKit deployment
47
63
 
48
- ## Multi-cloud
64
+ Deploy a SvelteKit app to AWS with a single component. Anvil provisions S3, CloudFront, ACM, Lambda (via Lambda Web Adapter), and Route53 — with HTTPS and a custom domain out of the box:
49
65
 
50
66
  ```typescript
51
67
  export default new App({
52
68
  run(ctx) {
53
- // AWS
54
- const bucket = new anvil.aws.Bucket('data', {
55
- dataClassification: 'sensitive',
69
+ const site = new anvil.aws.SvelteKitSite('web', {
70
+ domain: 'myapp.com',
56
71
  });
57
72
 
58
- // GCP
59
- const gcsBucket = new anvil.gcp.StorageBucket('backup', {
60
- dataClassification: 'internal',
61
- location: 'US',
62
- });
73
+ ctx.export('url', site.url);
63
74
  },
64
75
  });
65
76
  ```
66
77
 
67
78
  ## Overrides
68
79
 
69
- Every component accepts a `transform` argument to override the underlying resource config:
80
+ Every component accepts a `transform` argument to override the underlying resource config when you need to break from the defaults:
70
81
 
71
82
  ```typescript
72
83
  const bucket = new anvil.aws.Bucket('custom', {
@@ -77,12 +88,9 @@ const bucket = new anvil.aws.Bucket('custom', {
77
88
  });
78
89
  ```
79
90
 
80
- ## How it works
81
-
82
- Anvil is built on [Pulumi](https://www.pulumi.com/). Each component wraps one or more cloud resources with secure defaults. The `App` class handles config, providers, and exports so you write infrastructure — not boilerplate.
83
-
84
91
  ## Links
85
92
 
93
+ - [Docs](https://anvilcloud.dev)
86
94
  - [GitHub](https://github.com/DamienPace15/anvil)
87
95
  - [Python SDK](https://pypi.org/project/anvil-cloud/)
88
96
  - [Go SDK](https://pkg.go.dev/github.com/DamienPace15/anvil/sdk/go/anvil)
package/aws/bucket.ts CHANGED
@@ -7,11 +7,15 @@ import * as outputs from "../types/output";
7
7
  import * as utilities from "../utilities";
8
8
 
9
9
  import * as pulumiAws from "@pulumi/aws";
10
+ import * as grants from "../grants";
10
11
 
11
12
  export class Bucket extends pulumi.ComponentResource {
12
13
  /** @internal */
13
14
  public static readonly __pulumiType = 'anvil:aws:Bucket';
14
15
 
16
+ /** @internal Logical resource name for grant policy naming. */
17
+ private __name: string;
18
+
15
19
  /**
16
20
  * Returns true if the given object is an instance of Bucket. This is designed to work even
17
21
  * when multiple copies of the Pulumi SDK have been loaded into the same process.
@@ -23,6 +27,14 @@ export class Bucket extends pulumi.ComponentResource {
23
27
  return obj['__pulumiType'] === Bucket.__pulumiType;
24
28
  }
25
29
 
30
+ /**
31
+ * The ARN of the S3 bucket.
32
+ */
33
+ declare public /*out*/ readonly arn: pulumi.Output<string>;
34
+ /**
35
+ * The name of the S3 bucket.
36
+ */
37
+ declare public /*out*/ readonly bucketName: pulumi.Output<string>;
26
38
 
27
39
  /**
28
40
  * Create a Bucket resource with the given unique name, arguments, and options.
@@ -41,11 +53,99 @@ export class Bucket extends pulumi.ComponentResource {
41
53
  resourceInputs["dataClassification"] = args?.dataClassification;
42
54
  resourceInputs["lifecycle"] = args?.lifecycle;
43
55
  resourceInputs["transform"] = args?.transform;
56
+ resourceInputs["arn"] = undefined /*out*/;
57
+ resourceInputs["bucketName"] = undefined /*out*/;
44
58
  } else {
59
+ resourceInputs["arn"] = undefined /*out*/;
60
+ resourceInputs["bucketName"] = undefined /*out*/;
45
61
  }
46
62
  opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
47
63
  super(Bucket.__pulumiType, name, resourceInputs, opts, true /*remote*/);
64
+ this.__name = name;
48
65
  }
66
+
67
+ /**
68
+ * Grants read access (s3:GetObject, s3:ListBucket) on this bucket
69
+ * to the target compute resource's execution role.
70
+ *
71
+ * @param target - The compute resource to grant access to.
72
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
73
+ * @param opts - Optional grant options (justification for audit trail).
74
+ */
75
+ public grantRead(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void {
76
+ const name = `${this.__name}-${target.grantName()}-read`;
77
+ const arns = grants.buildResourceArns(this.arn, paths);
78
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket"], arns, opts);
79
+ }
80
+
81
+ /**
82
+ * Grants write access (s3:PutObject) on this bucket
83
+ * to the target compute resource's execution role.
84
+ *
85
+ * @param target - The compute resource to grant access to.
86
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
87
+ * @param opts - Optional grant options (justification for audit trail).
88
+ */
89
+ public grantWrite(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void {
90
+ const name = `${this.__name}-${target.grantName()}-write`;
91
+ const arns = grants.buildResourceArns(this.arn, paths);
92
+ grants.createGrant(this, name, target, ["s3:PutObject"], arns, opts);
93
+ }
94
+
95
+ /**
96
+ * Grants readwrite access (s3:GetObject, s3:ListBucket, s3:PutObject) on this bucket
97
+ * to the target compute resource's execution role.
98
+ *
99
+ * @param target - The compute resource to grant access to.
100
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
101
+ * @param opts - Optional grant options (justification for audit trail).
102
+ */
103
+ public grantReadWrite(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void {
104
+ const name = `${this.__name}-${target.grantName()}-readwrite`;
105
+ const arns = grants.buildResourceArns(this.arn, paths);
106
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket", "s3:PutObject"], arns, opts);
107
+ }
108
+
109
+ /**
110
+ * Grants delete access (s3:DeleteObject) on this bucket
111
+ * to the target compute resource's execution role.
112
+ *
113
+ * @param target - The compute resource to grant access to.
114
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
115
+ * @param opts - Optional grant options (justification for audit trail).
116
+ */
117
+ public grantDelete(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void {
118
+ const name = `${this.__name}-${target.grantName()}-delete`;
119
+ const arns = grants.buildResourceArns(this.arn, paths);
120
+ grants.createGrant(this, name, target, ["s3:DeleteObject"], arns, opts);
121
+ }
122
+
123
+ /**
124
+ * Grants full access (s3:GetObject, s3:ListBucket, s3:PutObject, s3:DeleteObject) on this bucket
125
+ * to the target compute resource's execution role.
126
+ *
127
+ * This is an escape hatch — prefer scoped grants (grantRead, grantWrite, etc.).
128
+ * A warning is logged if no justification is provided.
129
+ */
130
+ public grantFullAccess(target: grants.GrantTarget, opts?: grants.GrantOptions): void {
131
+ if (!opts?.justification) {
132
+ pulumi.log.warn(
133
+ `⚠ ${this.__name} → ${target.grantName()}: full access granted with no justification. ` +
134
+ `Consider scoping with grantRead, grantWrite, or grantDelete, ` +
135
+ `or add a justification.`,
136
+ this,
137
+ );
138
+ } else {
139
+ pulumi.log.info(
140
+ `ℹ ${this.__name} → ${target.grantName()}: full access granted. Justification: "${opts.justification}"`,
141
+ this,
142
+ );
143
+ }
144
+ const name = `${this.__name}-${target.grantName()}-fullaccess`;
145
+ const arns = grants.buildResourceArns(this.arn, undefined);
146
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteObject"], arns, opts);
147
+ }
148
+
49
149
  }
50
150
 
51
151
  /**
package/aws/lambda.ts CHANGED
@@ -7,11 +7,15 @@ import * as outputs from "../types/output";
7
7
  import * as utilities from "../utilities";
8
8
 
9
9
  import * as pulumiAws from "@pulumi/aws";
10
+ import * as grants from "../grants";
10
11
 
11
12
  export class Lambda extends pulumi.ComponentResource {
12
13
  /** @internal */
13
14
  public static readonly __pulumiType = 'anvil:aws:Lambda';
14
15
 
16
+ /** @internal Logical resource name for grant policy naming. */
17
+ private __name: string;
18
+
15
19
  /**
16
20
  * Returns true if the given object is an instance of Lambda. This is designed to work even
17
21
  * when multiple copies of the Pulumi SDK have been loaded into the same process.
@@ -23,6 +27,18 @@ export class Lambda extends pulumi.ComponentResource {
23
27
  return obj['__pulumiType'] === Lambda.__pulumiType;
24
28
  }
25
29
 
30
+ /**
31
+ * The ARN of the Lambda function.
32
+ */
33
+ declare public /*out*/ readonly arn: pulumi.Output<string>;
34
+ /**
35
+ * The name of the Lambda function.
36
+ */
37
+ declare public /*out*/ readonly functionName: pulumi.Output<string>;
38
+ /**
39
+ * The ARN of the Lambda's IAM execution role.
40
+ */
41
+ declare public /*out*/ readonly roleArn: pulumi.Output<string>;
26
42
 
27
43
  /**
28
44
  * Create a Lambda resource with the given unique name, arguments, and options.
@@ -41,11 +57,41 @@ export class Lambda extends pulumi.ComponentResource {
41
57
  resourceInputs["name"] = args?.name;
42
58
  resourceInputs["transform"] = args?.transform;
43
59
  resourceInputs["vpc"] = args?.vpc;
60
+ resourceInputs["arn"] = undefined /*out*/;
61
+ resourceInputs["functionName"] = undefined /*out*/;
62
+ resourceInputs["roleArn"] = undefined /*out*/;
44
63
  } else {
64
+ resourceInputs["arn"] = undefined /*out*/;
65
+ resourceInputs["functionName"] = undefined /*out*/;
66
+ resourceInputs["roleArn"] = undefined /*out*/;
45
67
  }
46
68
  opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
47
69
  super(Lambda.__pulumiType, name, resourceInputs, opts, true /*remote*/);
70
+ this.__name = name;
71
+ }
72
+
73
+ /**
74
+ * Grants invoke access (lambda:InvokeFunction) on this lambda
75
+ * to the target compute resource's execution role.
76
+ *
77
+ * @param target - The compute resource to grant access to.
78
+ * @param opts - Optional grant options (justification for audit trail).
79
+ */
80
+ public grantInvoke(target: grants.GrantTarget, opts?: grants.GrantOptions): void {
81
+ const name = `${this.__name}-${target.grantName()}-invoke`;
82
+ const arns = grants.buildResourceArns(this.arn, undefined);
83
+ grants.createGrant(this, name, target, ["lambda:InvokeFunction"], arns, opts);
48
84
  }
85
+ /** Implements GrantTarget — returns the logical resource name. */
86
+ public grantName(): string {
87
+ return this.__name;
88
+ }
89
+
90
+ /** Implements GrantTarget — returns the IAM execution role ARN. */
91
+ public grantRoleArn(): pulumi.Output<string> {
92
+ return this.roleArn;
93
+ }
94
+
49
95
  }
50
96
 
51
97
  /**
@@ -39,6 +39,7 @@ export class SvelteKitSite extends pulumi.ComponentResource {
39
39
  resourceInputs["domain"] = args?.domain;
40
40
  resourceInputs["environment"] = args?.environment;
41
41
  resourceInputs["path"] = args?.path;
42
+ resourceInputs["runtimeEnvironment"] = args?.runtimeEnvironment;
42
43
  resourceInputs["transform"] = args?.transform;
43
44
  resourceInputs["bucketName"] = undefined /*out*/;
44
45
  resourceInputs["cloudFrontDistributionId"] = undefined /*out*/;
@@ -62,7 +63,14 @@ export class SvelteKitSite extends pulumi.ComponentResource {
62
63
  */
63
64
  export interface SvelteKitSiteArgs {
64
65
  domain?: pulumi.Input<string>;
66
+ /**
67
+ * Environment vars available at BOTH build time and runtime. Values must be string literals since they're needed before the build runs. Available in SvelteKit's $env/static (build) and $env/dynamic (runtime).
68
+ */
65
69
  environment?: pulumi.Input<{[key: string]: pulumi.Input<string>}>;
66
70
  path?: pulumi.Input<string>;
71
+ /**
72
+ * Runtime-only environment vars set on the Lambda function. Supports Pulumi Output values (e.g. bucket.name, fn.arn). Only available in SvelteKit's $env/dynamic at request time, NOT during build/prerendering.
73
+ */
74
+ runtimeEnvironment?: pulumi.Input<string>;
67
75
  transform?: pulumi.Input<string>;
68
76
  }
@@ -1,11 +1,20 @@
1
1
  import * as pulumi from "@pulumi/pulumi";
2
2
  import * as inputs from "../types/input";
3
+ import * as grants from "../grants";
3
4
  export declare class Bucket extends pulumi.ComponentResource {
4
5
  /**
5
6
  * Returns true if the given object is an instance of Bucket. This is designed to work even
6
7
  * when multiple copies of the Pulumi SDK have been loaded into the same process.
7
8
  */
8
9
  static isInstance(obj: any): obj is Bucket;
10
+ /**
11
+ * The ARN of the S3 bucket.
12
+ */
13
+ readonly arn: pulumi.Output<string>;
14
+ /**
15
+ * The name of the S3 bucket.
16
+ */
17
+ readonly bucketName: pulumi.Output<string>;
9
18
  /**
10
19
  * Create a Bucket resource with the given unique name, arguments, and options.
11
20
  *
@@ -14,6 +23,50 @@ export declare class Bucket extends pulumi.ComponentResource {
14
23
  * @param opts A bag of options that control this resource's behavior.
15
24
  */
16
25
  constructor(name: string, args: BucketArgs, opts?: pulumi.ComponentResourceOptions);
26
+ /**
27
+ * Grants read access (s3:GetObject, s3:ListBucket) on this bucket
28
+ * to the target compute resource's execution role.
29
+ *
30
+ * @param target - The compute resource to grant access to.
31
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
32
+ * @param opts - Optional grant options (justification for audit trail).
33
+ */
34
+ grantRead(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void;
35
+ /**
36
+ * Grants write access (s3:PutObject) on this bucket
37
+ * to the target compute resource's execution role.
38
+ *
39
+ * @param target - The compute resource to grant access to.
40
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
41
+ * @param opts - Optional grant options (justification for audit trail).
42
+ */
43
+ grantWrite(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void;
44
+ /**
45
+ * Grants readwrite access (s3:GetObject, s3:ListBucket, s3:PutObject) on this bucket
46
+ * to the target compute resource's execution role.
47
+ *
48
+ * @param target - The compute resource to grant access to.
49
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
50
+ * @param opts - Optional grant options (justification for audit trail).
51
+ */
52
+ grantReadWrite(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void;
53
+ /**
54
+ * Grants delete access (s3:DeleteObject) on this bucket
55
+ * to the target compute resource's execution role.
56
+ *
57
+ * @param target - The compute resource to grant access to.
58
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
59
+ * @param opts - Optional grant options (justification for audit trail).
60
+ */
61
+ grantDelete(target: grants.GrantTarget, paths?: string[], opts?: grants.GrantOptions): void;
62
+ /**
63
+ * Grants full access (s3:GetObject, s3:ListBucket, s3:PutObject, s3:DeleteObject) on this bucket
64
+ * to the target compute resource's execution role.
65
+ *
66
+ * This is an escape hatch — prefer scoped grants (grantRead, grantWrite, etc.).
67
+ * A warning is logged if no justification is provided.
68
+ */
69
+ grantFullAccess(target: grants.GrantTarget, opts?: grants.GrantOptions): void;
17
70
  }
18
71
  /**
19
72
  * The set of arguments for constructing a Bucket resource.
package/bin/aws/bucket.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.Bucket = void 0;
6
6
  const pulumi = require("@pulumi/pulumi");
7
7
  const utilities = require("../utilities");
8
+ const grants = require("../grants");
8
9
  class Bucket extends pulumi.ComponentResource {
9
10
  /**
10
11
  * Returns true if the given object is an instance of Bucket. This is designed to work even
@@ -33,11 +34,88 @@ class Bucket extends pulumi.ComponentResource {
33
34
  resourceInputs["dataClassification"] = args?.dataClassification;
34
35
  resourceInputs["lifecycle"] = args?.lifecycle;
35
36
  resourceInputs["transform"] = args?.transform;
37
+ resourceInputs["arn"] = undefined /*out*/;
38
+ resourceInputs["bucketName"] = undefined /*out*/;
36
39
  }
37
40
  else {
41
+ resourceInputs["arn"] = undefined /*out*/;
42
+ resourceInputs["bucketName"] = undefined /*out*/;
38
43
  }
39
44
  opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
40
45
  super(Bucket.__pulumiType, name, resourceInputs, opts, true /*remote*/);
46
+ this.__name = name;
47
+ }
48
+ /**
49
+ * Grants read access (s3:GetObject, s3:ListBucket) on this bucket
50
+ * to the target compute resource's execution role.
51
+ *
52
+ * @param target - The compute resource to grant access to.
53
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
54
+ * @param opts - Optional grant options (justification for audit trail).
55
+ */
56
+ grantRead(target, paths, opts) {
57
+ const name = `${this.__name}-${target.grantName()}-read`;
58
+ const arns = grants.buildResourceArns(this.arn, paths);
59
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket"], arns, opts);
60
+ }
61
+ /**
62
+ * Grants write access (s3:PutObject) on this bucket
63
+ * to the target compute resource's execution role.
64
+ *
65
+ * @param target - The compute resource to grant access to.
66
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
67
+ * @param opts - Optional grant options (justification for audit trail).
68
+ */
69
+ grantWrite(target, paths, opts) {
70
+ const name = `${this.__name}-${target.grantName()}-write`;
71
+ const arns = grants.buildResourceArns(this.arn, paths);
72
+ grants.createGrant(this, name, target, ["s3:PutObject"], arns, opts);
73
+ }
74
+ /**
75
+ * Grants readwrite access (s3:GetObject, s3:ListBucket, s3:PutObject) on this bucket
76
+ * to the target compute resource's execution role.
77
+ *
78
+ * @param target - The compute resource to grant access to.
79
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
80
+ * @param opts - Optional grant options (justification for audit trail).
81
+ */
82
+ grantReadWrite(target, paths, opts) {
83
+ const name = `${this.__name}-${target.grantName()}-readwrite`;
84
+ const arns = grants.buildResourceArns(this.arn, paths);
85
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket", "s3:PutObject"], arns, opts);
86
+ }
87
+ /**
88
+ * Grants delete access (s3:DeleteObject) on this bucket
89
+ * to the target compute resource's execution role.
90
+ *
91
+ * @param target - The compute resource to grant access to.
92
+ * @param paths - Optional array of path prefixes to scope access (e.g. ["uploads/*"]).
93
+ * @param opts - Optional grant options (justification for audit trail).
94
+ */
95
+ grantDelete(target, paths, opts) {
96
+ const name = `${this.__name}-${target.grantName()}-delete`;
97
+ const arns = grants.buildResourceArns(this.arn, paths);
98
+ grants.createGrant(this, name, target, ["s3:DeleteObject"], arns, opts);
99
+ }
100
+ /**
101
+ * Grants full access (s3:GetObject, s3:ListBucket, s3:PutObject, s3:DeleteObject) on this bucket
102
+ * to the target compute resource's execution role.
103
+ *
104
+ * This is an escape hatch — prefer scoped grants (grantRead, grantWrite, etc.).
105
+ * A warning is logged if no justification is provided.
106
+ */
107
+ grantFullAccess(target, opts) {
108
+ if (!opts?.justification) {
109
+ pulumi.log.warn(`⚠ ${this.__name} → ${target.grantName()}: full access granted with no justification. ` +
110
+ `Consider scoping with grantRead, grantWrite, or grantDelete, ` +
111
+ `or add a justification.`, this);
112
+ }
113
+ else {
114
+ pulumi.log.info(`ℹ ${this.__name} → ${target.grantName()}: full access granted. Justification: "${opts.justification}"`, this);
115
+ }
116
+ const name = `${this.__name}-${target.grantName()}-fullaccess`;
117
+ const arns = grants.buildResourceArns(this.arn, undefined);
118
+ grants.createGrant(this, name, target, ["s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteObject"], arns, opts);
41
119
  }
42
120
  }
43
121
  exports.Bucket = Bucket;
@@ -1 +1 @@
1
- {"version":3,"file":"bucket.js","sourceRoot":"","sources":["../../aws/bucket.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AAGzC,0CAA0C;AAI1C,MAAa,MAAO,SAAQ,MAAM,CAAC,iBAAiB;IAIhD;;;OAGG;IACI,MAAM,CAAC,UAAU,CAAC,GAAQ;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE;YACnC,OAAO,KAAK,CAAC;SAChB;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC;IACvD,CAAC;IAGD;;;;;;OAMG;IACH,YAAY,IAAY,EAAE,IAAgB,EAAE,IAAsC;QAC9E,IAAI,cAAc,GAAkB,EAAE,CAAC;QACvC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,IAAI,IAAI,EAAE,kBAAkB,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACrD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;aACrE;YACD,cAAc,CAAC,oBAAoB,CAAC,GAAG,IAAI,EAAE,kBAAkB,CAAC;YAChE,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;YAC9C,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;SACjD;aAAM;SACN;QACD,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5E,CAAC;;AArCL,wBAsCC;AArCG,gBAAgB;AACO,mBAAY,GAAG,kBAAkB,CAAC"}
1
+ {"version":3,"file":"bucket.js","sourceRoot":"","sources":["../../aws/bucket.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,24 @@
1
1
  import * as pulumi from "@pulumi/pulumi";
2
2
  import * as inputs from "../types/input";
3
+ import * as grants from "../grants";
3
4
  export declare class Lambda extends pulumi.ComponentResource {
4
5
  /**
5
6
  * Returns true if the given object is an instance of Lambda. This is designed to work even
6
7
  * when multiple copies of the Pulumi SDK have been loaded into the same process.
7
8
  */
8
9
  static isInstance(obj: any): obj is Lambda;
10
+ /**
11
+ * The ARN of the Lambda function.
12
+ */
13
+ readonly arn: pulumi.Output<string>;
14
+ /**
15
+ * The name of the Lambda function.
16
+ */
17
+ readonly functionName: pulumi.Output<string>;
18
+ /**
19
+ * The ARN of the Lambda's IAM execution role.
20
+ */
21
+ readonly roleArn: pulumi.Output<string>;
9
22
  /**
10
23
  * Create a Lambda resource with the given unique name, arguments, and options.
11
24
  *
@@ -14,6 +27,18 @@ export declare class Lambda extends pulumi.ComponentResource {
14
27
  * @param opts A bag of options that control this resource's behavior.
15
28
  */
16
29
  constructor(name: string, args: LambdaArgs, opts?: pulumi.ComponentResourceOptions);
30
+ /**
31
+ * Grants invoke access (lambda:InvokeFunction) on this lambda
32
+ * to the target compute resource's execution role.
33
+ *
34
+ * @param target - The compute resource to grant access to.
35
+ * @param opts - Optional grant options (justification for audit trail).
36
+ */
37
+ grantInvoke(target: grants.GrantTarget, opts?: grants.GrantOptions): void;
38
+ /** Implements GrantTarget — returns the logical resource name. */
39
+ grantName(): string;
40
+ /** Implements GrantTarget — returns the IAM execution role ARN. */
41
+ grantRoleArn(): pulumi.Output<string>;
17
42
  }
18
43
  /**
19
44
  * The set of arguments for constructing a Lambda resource.
package/bin/aws/lambda.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.Lambda = void 0;
6
6
  const pulumi = require("@pulumi/pulumi");
7
7
  const utilities = require("../utilities");
8
+ const grants = require("../grants");
8
9
  class Lambda extends pulumi.ComponentResource {
9
10
  /**
10
11
  * Returns true if the given object is an instance of Lambda. This is designed to work even
@@ -33,11 +34,38 @@ class Lambda extends pulumi.ComponentResource {
33
34
  resourceInputs["name"] = args?.name;
34
35
  resourceInputs["transform"] = args?.transform;
35
36
  resourceInputs["vpc"] = args?.vpc;
37
+ resourceInputs["arn"] = undefined /*out*/;
38
+ resourceInputs["functionName"] = undefined /*out*/;
39
+ resourceInputs["roleArn"] = undefined /*out*/;
36
40
  }
37
41
  else {
42
+ resourceInputs["arn"] = undefined /*out*/;
43
+ resourceInputs["functionName"] = undefined /*out*/;
44
+ resourceInputs["roleArn"] = undefined /*out*/;
38
45
  }
39
46
  opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
40
47
  super(Lambda.__pulumiType, name, resourceInputs, opts, true /*remote*/);
48
+ this.__name = name;
49
+ }
50
+ /**
51
+ * Grants invoke access (lambda:InvokeFunction) on this lambda
52
+ * to the target compute resource's execution role.
53
+ *
54
+ * @param target - The compute resource to grant access to.
55
+ * @param opts - Optional grant options (justification for audit trail).
56
+ */
57
+ grantInvoke(target, opts) {
58
+ const name = `${this.__name}-${target.grantName()}-invoke`;
59
+ const arns = grants.buildResourceArns(this.arn, undefined);
60
+ grants.createGrant(this, name, target, ["lambda:InvokeFunction"], arns, opts);
61
+ }
62
+ /** Implements GrantTarget — returns the logical resource name. */
63
+ grantName() {
64
+ return this.__name;
65
+ }
66
+ /** Implements GrantTarget — returns the IAM execution role ARN. */
67
+ grantRoleArn() {
68
+ return this.roleArn;
41
69
  }
42
70
  }
43
71
  exports.Lambda = Lambda;
@@ -1 +1 @@
1
- {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../aws/lambda.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AAGzC,0CAA0C;AAI1C,MAAa,MAAO,SAAQ,MAAM,CAAC,iBAAiB;IAIhD;;;OAGG;IACI,MAAM,CAAC,UAAU,CAAC,GAAQ;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE;YACnC,OAAO,KAAK,CAAC;SAChB;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC;IACvD,CAAC;IAGD;;;;;;OAMG;IACH,YAAY,IAAY,EAAE,IAAgB,EAAE,IAAsC;QAC9E,IAAI,cAAc,GAAkB,EAAE,CAAC;QACvC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACvC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;aACvD;YACD,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC;YACpC,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;YAC9C,cAAc,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC;SACrC;aAAM;SACN;QACD,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5E,CAAC;;AArCL,wBAsCC;AArCG,gBAAgB;AACO,mBAAY,GAAG,kBAAkB,CAAC"}
1
+ {"version":3,"file":"lambda.js","sourceRoot":"","sources":["../../aws/lambda.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AAGzC,0CAA0C;AAG1C,oCAAoC;AAEpC,MAAa,MAAO,SAAQ,MAAM,CAAC,iBAAiB;IAOhD;;;OAGG;IACI,MAAM,CAAC,UAAU,CAAC,GAAQ;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE;YACnC,OAAO,KAAK,CAAC;SAChB;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC;IACvD,CAAC;IAeD;;;;;;OAMG;IACH,YAAY,IAAY,EAAE,IAAgB,EAAE,IAAsC;QAC9E,IAAI,cAAc,GAAkB,EAAE,CAAC;QACvC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACvC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;aACvD;YACD,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC;YACpC,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;YAC9C,cAAc,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC;YAClC,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC1C,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SACjD;aAAM;YACH,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC1C,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SACjD;QACD,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;;OAMG;IACI,WAAW,CAAC,MAA0B,EAAE,IAA0B;QACrE,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC;QAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC3D,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAClF,CAAC;IACD,kEAAkE;IAC3D,SAAS;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,mEAAmE;IAC5D,YAAY;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;;AAjFL,wBAmFC;AAlFG,gBAAgB;AACO,mBAAY,GAAG,kBAAkB,CAAC"}
@@ -24,9 +24,16 @@ export declare class SvelteKitSite extends pulumi.ComponentResource {
24
24
  */
25
25
  export interface SvelteKitSiteArgs {
26
26
  domain?: pulumi.Input<string>;
27
+ /**
28
+ * Environment vars available at BOTH build time and runtime. Values must be string literals since they're needed before the build runs. Available in SvelteKit's $env/static (build) and $env/dynamic (runtime).
29
+ */
27
30
  environment?: pulumi.Input<{
28
31
  [key: string]: pulumi.Input<string>;
29
32
  }>;
30
33
  path?: pulumi.Input<string>;
34
+ /**
35
+ * Runtime-only environment vars set on the Lambda function. Supports Pulumi Output values (e.g. bucket.name, fn.arn). Only available in SvelteKit's $env/dynamic at request time, NOT during build/prerendering.
36
+ */
37
+ runtimeEnvironment?: pulumi.Input<string>;
31
38
  transform?: pulumi.Input<string>;
32
39
  }
@@ -30,6 +30,7 @@ class SvelteKitSite extends pulumi.ComponentResource {
30
30
  resourceInputs["domain"] = args?.domain;
31
31
  resourceInputs["environment"] = args?.environment;
32
32
  resourceInputs["path"] = args?.path;
33
+ resourceInputs["runtimeEnvironment"] = args?.runtimeEnvironment;
33
34
  resourceInputs["transform"] = args?.transform;
34
35
  resourceInputs["bucketName"] = undefined /*out*/;
35
36
  resourceInputs["cloudFrontDistributionId"] = undefined /*out*/;
@@ -1 +1 @@
1
- {"version":3,"file":"svelteKitSite.js","sourceRoot":"","sources":["../../aws/svelteKitSite.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AACzC,0CAA0C;AAE1C,MAAa,aAAc,SAAQ,MAAM,CAAC,iBAAiB;IAIvD;;;OAGG;IACI,MAAM,CAAC,UAAU,CAAC,GAAQ;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE;YACnC,OAAO,KAAK,CAAC;SAChB;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,aAAa,CAAC,YAAY,CAAC;IAC9D,CAAC;IAQD;;;;;;OAMG;IACH,YAAY,IAAY,EAAE,IAAwB,EAAE,IAAsC;QACtF,IAAI,cAAc,GAAkB,EAAE,CAAC;QACvC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,cAAc,CAAC,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC;YACxC,cAAc,CAAC,aAAa,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC;YAClD,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC;YACpC,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;YAC9C,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,0BAA0B,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC/D,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SAC7C;aAAM;YACH,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,0BAA0B,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC/D,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SAC7C;QACD,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;;AAlDL,sCAmDC;AAlDG,gBAAgB;AACO,0BAAY,GAAG,yBAAyB,CAAC"}
1
+ {"version":3,"file":"svelteKitSite.js","sourceRoot":"","sources":["../../aws/svelteKitSite.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AACzC,0CAA0C;AAE1C,MAAa,aAAc,SAAQ,MAAM,CAAC,iBAAiB;IAIvD;;;OAGG;IACI,MAAM,CAAC,UAAU,CAAC,GAAQ;QAC7B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE;YACnC,OAAO,KAAK,CAAC;SAChB;QACD,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,aAAa,CAAC,YAAY,CAAC;IAC9D,CAAC;IAQD;;;;;;OAMG;IACH,YAAY,IAAY,EAAE,IAAwB,EAAE,IAAsC;QACtF,IAAI,cAAc,GAAkB,EAAE,CAAC;QACvC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,cAAc,CAAC,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC;YACxC,cAAc,CAAC,aAAa,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC;YAClD,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC;YACpC,cAAc,CAAC,oBAAoB,CAAC,GAAG,IAAI,EAAE,kBAAkB,CAAC;YAChE,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC;YAC9C,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,0BAA0B,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC/D,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SAC7C;aAAM;YACH,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,0BAA0B,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YAC/D,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACjD,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;YACnD,cAAc,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC;SAC7C;QACD,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;;AAnDL,sCAoDC;AAnDG,gBAAgB;AACO,0BAAY,GAAG,yBAAyB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import * as pulumi from '@pulumi/pulumi';
2
+ /**
3
+ * GrantTarget is any Anvil compute resource that can receive IAM permissions.
4
+ * Compute resources (Lambda, SvelteKitSite, etc.) satisfy this interface.
5
+ */
6
+ export interface GrantTarget {
7
+ /**
8
+ * The logical resource name passed to the constructor.
9
+ */
10
+ grantName(): string;
11
+ /**
12
+ * The ARN of the IAM execution role attached to this compute resource.
13
+ */
14
+ grantRoleArn(): pulumi.Output<string>;
15
+ }
16
+ /**
17
+ * Optional metadata for grant methods.
18
+ */
19
+ export interface GrantOptions {
20
+ /**
21
+ * Documents why this grant is needed.
22
+ * Stored as a tag on the generated IAM policy resource for audit purposes.
23
+ */
24
+ justification?: string;
25
+ }
package/bin/grants.js ADDED
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ // sdk/nodejs/grants.ts
3
+ // Hand-written. Backed up/restored during gen-sdk like app.ts and block.ts.
4
+ //
5
+ // Provides the runtime grant execution for all resource grant methods.
6
+ // Each resource's grant methods (injected by fix-sdk-grants.js) delegate here.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.buildResourceArns = exports.createGrant = void 0;
9
+ const pulumi = require("@pulumi/pulumi");
10
+ const aws = require("@pulumi/aws");
11
+ /**
12
+ * Creates a scoped IAM RolePolicy granting the specified actions on the
13
+ * specified resource ARNs to the target's execution role.
14
+ *
15
+ * This is the core engine that all resource-specific grant methods delegate to.
16
+ *
17
+ * @internal
18
+ */
19
+ function createGrant(parent, name, target, actions, resourceArns, opts) {
20
+ const policyDocument = pulumi.all(resourceArns).apply((arns) => JSON.stringify({
21
+ Version: '2012-10-17',
22
+ Statement: [
23
+ {
24
+ Effect: 'Allow',
25
+ Action: actions,
26
+ Resource: arns,
27
+ },
28
+ ],
29
+ }));
30
+ // Extract role name from ARN (everything after the last "/")
31
+ const roleName = target.grantRoleArn().apply((arn) => {
32
+ const idx = arn.lastIndexOf('/');
33
+ return idx >= 0 ? arn.substring(idx + 1) : arn;
34
+ });
35
+ // Justification is stored in the resource name suffix for audit trail.
36
+ // Future: compliance audit trail (Pro tier) will capture this metadata separately.
37
+ const policyName = opts?.justification
38
+ ? `${name}-${sanitize(opts.justification)}`
39
+ : name;
40
+ new aws.iam.RolePolicy(policyName, {
41
+ role: roleName,
42
+ policy: policyDocument,
43
+ }, { parent });
44
+ }
45
+ exports.createGrant = createGrant;
46
+ /** @internal Sanitize a string for use in resource names. */
47
+ function sanitize(s) {
48
+ return s
49
+ .toLowerCase()
50
+ .replace(/[^a-z0-9]+/g, '-')
51
+ .slice(0, 40);
52
+ }
53
+ /**
54
+ * Builds the list of ARNs for a grant based on a base ARN and optional path scoping.
55
+ *
56
+ * - No paths: grants access to the entire resource (baseArn + baseArn/*)
57
+ * - With paths: grants access to baseArn (for list operations) + each scoped path
58
+ *
59
+ * @internal
60
+ */
61
+ function buildResourceArns(baseArn, paths) {
62
+ const arns = [baseArn];
63
+ if (!paths || paths.length === 0) {
64
+ arns.push(pulumi.interpolate `${baseArn}/*`);
65
+ }
66
+ else {
67
+ for (const p of paths) {
68
+ arns.push(pulumi.interpolate `${baseArn}/${p}`);
69
+ }
70
+ }
71
+ return arns;
72
+ }
73
+ exports.buildResourceArns = buildResourceArns;
74
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../grants.ts"],"names":[],"mappings":";AAAA,uBAAuB;AACvB,4EAA4E;AAC5E,EAAE;AACF,uEAAuE;AACvE,+EAA+E;;;AAE/E,yCAAyC;AACzC,mCAAmC;AA6BnC;;;;;;;GAOG;AACH,SAAgB,WAAW,CACzB,MAAuB,EACvB,IAAY,EACZ,MAAmB,EACnB,OAAiB,EACjB,YAAqC,EACrC,IAAmB;IAEnB,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7D,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,YAAY;QACrB,SAAS,EAAE;YACT;gBACE,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE,IAAI;aACf;SACF;KACF,CAAC,CACH,CAAC;IAEF,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACnD,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,uEAAuE;IACvE,mFAAmF;IACnF,MAAM,UAAU,GAAG,IAAI,EAAE,aAAa;QACpC,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE;QAC3C,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CACpB,UAAU,EACV;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,cAAc;KACvB,EACD,EAAE,MAAM,EAAE,CACX,CAAC;AACJ,CAAC;AAzCD,kCAyCC;AAED,6DAA6D;AAC7D,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC;SACL,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAC/B,OAA8B,EAC9B,KAAgB;IAEhB,MAAM,IAAI,GAA4B,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAA,GAAG,OAAO,IAAI,CAAC,CAAC;KAC7C;SAAM;QACL,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE;YACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAA,GAAG,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;SAChD;KACF;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAfD,8CAeC"}
package/bin/index.d.ts CHANGED
@@ -8,6 +8,7 @@ import * as types from "./types";
8
8
  export { aws, gcp, types, };
9
9
  export { App, AppConfig, Context, AwsProviderConfig, GcpProviderConfig, DefaultsConfig } from "./app";
10
10
  export { Block, BlockArgs } from "./block";
11
+ export * from "./grants";
11
12
  export { ComponentResource, ComponentResourceOptions, CustomResource, ResourceOptions, ProviderResource, Config, output, all, secret, interpolate, concat, getProject, getStack, } from "@pulumi/pulumi";
12
13
  export type { Output, Input, Inputs } from "@pulumi/pulumi";
13
14
  export { pulumi };
package/bin/index.js CHANGED
@@ -1,6 +1,20 @@
1
1
  "use strict";
2
2
  // *** WARNING: this file was generated by pulumi-language-nodejs. ***
3
3
  // *** Do not edit by hand unless you're certain you know what you are doing! ***
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
4
18
  Object.defineProperty(exports, "__esModule", { value: true });
5
19
  exports.pulumi = exports.getStack = exports.getProject = exports.concat = exports.interpolate = exports.secret = exports.all = exports.output = exports.Config = exports.ProviderResource = exports.CustomResource = exports.ComponentResource = exports.Block = exports.App = exports.types = exports.gcp = exports.aws = exports.Provider = void 0;
6
20
  const pulumi = require("@pulumi/pulumi");
@@ -30,6 +44,8 @@ Object.defineProperty(exports, "App", { enumerable: true, get: function () { ret
30
44
  // Hand-written Block class
31
45
  var block_1 = require("./block");
32
46
  Object.defineProperty(exports, "Block", { enumerable: true, get: function () { return block_1.Block; } });
47
+ // Grant helpers
48
+ __exportStar(require("./grants"), exports);
33
49
  // Re-exported Pulumi primitives
34
50
  // Users can import anvil.Output, anvil.ComponentResource, etc. without @pulumi/pulumi
35
51
  var pulumi_1 = require("@pulumi/pulumi");
package/bin/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;AAEjF,yCAAyC;AAyDhC,wBAAM;AAxDf,yCAAyC;AAK5B,QAAA,QAAQ,GAAyC,IAAW,CAAC;AAC1E,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;AAGvE,sBAAsB;AACtB,6BAA6B;AAKzB,kBAAG;AAJP,6BAA6B;AAKzB,kBAAG;AAJP,iCAAiC;AAK7B,sBAAK;AAET,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,OAAO,EAAE;IAC5C,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE;IAC/B,iBAAiB,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,GAAW,EAA2B,EAAE;QACpF,IAAI,IAAI,KAAK,wBAAwB,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;SACpD;QACD,OAAO,IAAI,gBAAQ,CAAC,IAAI,EAAO,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;CACJ,CAAC,CAAC;AAEH,yBAAyB;AACzB,6BAAsG;AAA7F,0FAAA,GAAG,OAAA;AAEZ,2BAA2B;AAC3B,iCAA2C;AAAlC,8FAAA,KAAK,OAAA;AAEd,gCAAgC;AAChC,sFAAsF;AACtF,yCAcwB;AAbtB,2GAAA,iBAAiB,OAAA;AAEjB,wGAAA,cAAc,OAAA;AAEd,0GAAA,gBAAgB,OAAA;AAChB,gGAAA,MAAM,OAAA;AACN,gGAAA,MAAM,OAAA;AACN,6FAAA,GAAG,OAAA;AACH,gGAAA,MAAM,OAAA;AACN,qGAAA,WAAW,OAAA;AACX,gGAAA,MAAM,OAAA;AACN,oGAAA,UAAU,OAAA;AACV,kGAAA,QAAQ,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,iFAAiF;;;;;;;;;;;;;;;;;AAEjF,yCAAyC;AA4DhC,wBAAM;AA3Df,yCAAyC;AAK5B,QAAA,QAAQ,GAAyC,IAAW,CAAC;AAC1E,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;AAGvE,sBAAsB;AACtB,6BAA6B;AAKzB,kBAAG;AAJP,6BAA6B;AAKzB,kBAAG;AAJP,iCAAiC;AAK7B,sBAAK;AAET,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,OAAO,EAAE;IAC5C,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE;IAC/B,iBAAiB,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,GAAW,EAA2B,EAAE;QACpF,IAAI,IAAI,KAAK,wBAAwB,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;SACpD;QACD,OAAO,IAAI,gBAAQ,CAAC,IAAI,EAAO,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;CACJ,CAAC,CAAC;AAEH,yBAAyB;AACzB,6BAAsG;AAA7F,0FAAA,GAAG,OAAA;AAEZ,2BAA2B;AAC3B,iCAA2C;AAAlC,8FAAA,KAAK,OAAA;AAEd,gBAAgB;AAChB,2CAAyB;AAEzB,gCAAgC;AAChC,sFAAsF;AACtF,yCAcwB;AAbtB,2GAAA,iBAAiB,OAAA;AAEjB,wGAAA,cAAc,OAAA;AAEd,0GAAA,gBAAgB,OAAA;AAChB,gGAAA,MAAM,OAAA;AACN,gGAAA,MAAM,OAAA;AACN,6FAAA,GAAG,OAAA;AACH,gGAAA,MAAM,OAAA;AACN,qGAAA,WAAW,OAAA;AACX,gGAAA,MAAM,OAAA;AACN,oGAAA,UAAU,OAAA;AACV,kGAAA,QAAQ,OAAA"}
package/bin/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-cloud/sdk",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "scripts": {
5
5
  "build": "tsc && cp package.json bin/"
6
6
  },
package/grants.ts ADDED
@@ -0,0 +1,119 @@
1
+ // sdk/nodejs/grants.ts
2
+ // Hand-written. Backed up/restored during gen-sdk like app.ts and block.ts.
3
+ //
4
+ // Provides the runtime grant execution for all resource grant methods.
5
+ // Each resource's grant methods (injected by fix-sdk-grants.js) delegate here.
6
+
7
+ import * as pulumi from '@pulumi/pulumi';
8
+ import * as aws from '@pulumi/aws';
9
+
10
+ /**
11
+ * GrantTarget is any Anvil compute resource that can receive IAM permissions.
12
+ * Compute resources (Lambda, SvelteKitSite, etc.) satisfy this interface.
13
+ */
14
+ export interface GrantTarget {
15
+ /**
16
+ * The logical resource name passed to the constructor.
17
+ */
18
+ grantName(): string;
19
+
20
+ /**
21
+ * The ARN of the IAM execution role attached to this compute resource.
22
+ */
23
+ grantRoleArn(): pulumi.Output<string>;
24
+ }
25
+
26
+ /**
27
+ * Optional metadata for grant methods.
28
+ */
29
+ export interface GrantOptions {
30
+ /**
31
+ * Documents why this grant is needed.
32
+ * Stored as a tag on the generated IAM policy resource for audit purposes.
33
+ */
34
+ justification?: string;
35
+ }
36
+
37
+ /**
38
+ * Creates a scoped IAM RolePolicy granting the specified actions on the
39
+ * specified resource ARNs to the target's execution role.
40
+ *
41
+ * This is the core engine that all resource-specific grant methods delegate to.
42
+ *
43
+ * @internal
44
+ */
45
+ export function createGrant(
46
+ parent: pulumi.Resource,
47
+ name: string,
48
+ target: GrantTarget,
49
+ actions: string[],
50
+ resourceArns: pulumi.Output<string>[],
51
+ opts?: GrantOptions
52
+ ): void {
53
+ const policyDocument = pulumi.all(resourceArns).apply((arns) =>
54
+ JSON.stringify({
55
+ Version: '2012-10-17',
56
+ Statement: [
57
+ {
58
+ Effect: 'Allow',
59
+ Action: actions,
60
+ Resource: arns,
61
+ },
62
+ ],
63
+ })
64
+ );
65
+
66
+ // Extract role name from ARN (everything after the last "/")
67
+ const roleName = target.grantRoleArn().apply((arn) => {
68
+ const idx = arn.lastIndexOf('/');
69
+ return idx >= 0 ? arn.substring(idx + 1) : arn;
70
+ });
71
+
72
+ // Justification is stored in the resource name suffix for audit trail.
73
+ // Future: compliance audit trail (Pro tier) will capture this metadata separately.
74
+ const policyName = opts?.justification
75
+ ? `${name}-${sanitize(opts.justification)}`
76
+ : name;
77
+
78
+ new aws.iam.RolePolicy(
79
+ policyName,
80
+ {
81
+ role: roleName,
82
+ policy: policyDocument,
83
+ },
84
+ { parent }
85
+ );
86
+ }
87
+
88
+ /** @internal Sanitize a string for use in resource names. */
89
+ function sanitize(s: string): string {
90
+ return s
91
+ .toLowerCase()
92
+ .replace(/[^a-z0-9]+/g, '-')
93
+ .slice(0, 40);
94
+ }
95
+
96
+ /**
97
+ * Builds the list of ARNs for a grant based on a base ARN and optional path scoping.
98
+ *
99
+ * - No paths: grants access to the entire resource (baseArn + baseArn/*)
100
+ * - With paths: grants access to baseArn (for list operations) + each scoped path
101
+ *
102
+ * @internal
103
+ */
104
+ export function buildResourceArns(
105
+ baseArn: pulumi.Output<string>,
106
+ paths?: string[]
107
+ ): pulumi.Output<string>[] {
108
+ const arns: pulumi.Output<string>[] = [baseArn];
109
+
110
+ if (!paths || paths.length === 0) {
111
+ arns.push(pulumi.interpolate`${baseArn}/*`);
112
+ } else {
113
+ for (const p of paths) {
114
+ arns.push(pulumi.interpolate`${baseArn}/${p}`);
115
+ }
116
+ }
117
+
118
+ return arns;
119
+ }
package/index.ts CHANGED
@@ -37,6 +37,9 @@ export { App, AppConfig, Context, AwsProviderConfig, GcpProviderConfig, Defaults
37
37
  // Hand-written Block class
38
38
  export { Block, BlockArgs } from "./block";
39
39
 
40
+ // Grant helpers
41
+ export * from "./grants";
42
+
40
43
  // Re-exported Pulumi primitives
41
44
  // Users can import anvil.Output, anvil.ComponentResource, etc. without @pulumi/pulumi
42
45
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-cloud/sdk",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "scripts": {
5
5
  "build": "tsc && cp package.json bin/"
6
6
  },