@jaypie/constructs 1.2.49 → 1.2.51

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.
@@ -1,9 +1,11 @@
1
1
  import { Role } from "aws-cdk-lib/aws-iam";
2
2
  import { Construct } from "constructs";
3
3
  export interface JaypieGitHubDeployRoleProps {
4
+ ecr?: boolean;
4
5
  oidcProviderArn?: string;
5
6
  output?: boolean | string;
6
7
  repoRestriction?: string;
8
+ sponsor?: string;
7
9
  }
8
10
  export declare class JaypieGitHubDeployRole extends Construct {
9
11
  private readonly _role;
package/dist/esm/index.js CHANGED
@@ -945,12 +945,16 @@ function exportEnvName$1(name, env = process.env) {
945
945
  }
946
946
  class JaypieEnvSecret extends Construct {
947
947
  constructor(scope, idOrEnvKey, props) {
948
- // Check if idOrEnvKey should be treated as envKey:
949
- // - No props provided OR props.envKey is not set
950
- // - AND idOrEnvKey exists as a non-empty string in process.env
948
+ // Shorthand detection: treat idOrEnvKey as envKey when envKey prop is
949
+ // not set and idOrEnvKey either looks like a SCREAMING_SNAKE_CASE env
950
+ // var name or is already present in process.env. Convention-based
951
+ // detection ensures missing env vars still go through envKey validation
952
+ // instead of silently creating an empty secret.
953
+ const looksLikeEnvKey = /^[A-Z][A-Z0-9_]*$/.test(idOrEnvKey);
951
954
  const treatAsEnvKey = (!props || props.envKey === undefined) &&
952
- typeof process.env[idOrEnvKey] === "string" &&
953
- process.env[idOrEnvKey] !== "";
955
+ (looksLikeEnvKey ||
956
+ (typeof process.env[idOrEnvKey] === "string" &&
957
+ process.env[idOrEnvKey] !== ""));
954
958
  const id = treatAsEnvKey ? `EnvSecret_${idOrEnvKey}` : idOrEnvKey;
955
959
  super(scope, id);
956
960
  const { consumer = checkEnvIsConsumer$1(), envKey: envKeyProp, export: exportParam, generateSecretString, provider = checkEnvIsProvider$1(), removalPolicy, roleTag, vendorTag, value, } = props || {};
@@ -3259,23 +3263,33 @@ class JaypieExpressLambda extends JaypieLambda {
3259
3263
  }
3260
3264
  }
3261
3265
 
3266
+ const ECR_PUSH_ACTIONS = [
3267
+ "ecr:BatchCheckLayerAvailability",
3268
+ "ecr:BatchGetImage",
3269
+ "ecr:CompleteLayerUpload",
3270
+ "ecr:CreateRepository",
3271
+ "ecr:DescribeRepositories",
3272
+ "ecr:InitiateLayerUpload",
3273
+ "ecr:PutImage",
3274
+ "ecr:UploadLayerPart",
3275
+ ];
3262
3276
  class JaypieGitHubDeployRole extends Construct {
3263
3277
  constructor(scope, id = "GitHubDeployRole", props = {}) {
3264
3278
  super(scope, id);
3265
- const { oidcProviderArn = Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, } = props;
3279
+ const { ecr = true, oidcProviderArn = Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, sponsor: propsSponsor, } = props;
3266
3280
  // Extract account ID from the scope
3267
3281
  const accountId = Stack.of(this).account;
3268
- // Resolve repoRestriction from props or environment variables
3282
+ // Resolve repoRestriction and sponsor from props or environment variables
3283
+ const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
3284
+ const envRepoOrganization = envRepo ? envRepo.split("/")[0] : undefined;
3269
3285
  let repoRestriction = propsRepoRestriction;
3270
3286
  if (!repoRestriction) {
3271
- const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
3272
- if (!envRepo) {
3287
+ if (!envRepoOrganization) {
3273
3288
  throw new ConfigurationError("No repoRestriction provided. Set repoRestriction prop, CDK_ENV_REPO, or PROJECT_REPO environment variable");
3274
3289
  }
3275
- // Extract organization from owner/repo format and create org-wide restriction
3276
- const organization = envRepo.split("/")[0];
3277
- repoRestriction = `repo:${organization}/*:*`;
3290
+ repoRestriction = `repo:${envRepoOrganization}/*:*`;
3278
3291
  }
3292
+ const sponsor = propsSponsor || process.env.PROJECT_SPONSOR || envRepoOrganization;
3279
3293
  // Create the IAM role
3280
3294
  this._role = new Role(this, "GitHubActionsRole", {
3281
3295
  assumedBy: new FederatedPrincipal(oidcProviderArn, {
@@ -3323,6 +3337,22 @@ class JaypieGitHubDeployRole extends Construct {
3323
3337
  "arn:aws:iam::*:role/cdk-readOnlyRole",
3324
3338
  ],
3325
3339
  }));
3340
+ // Grant ECR auth + push scoped to <sponsor>-* repositories
3341
+ if (ecr) {
3342
+ if (!sponsor) {
3343
+ throw new ConfigurationError("Cannot grant default ECR permissions without a sponsor. Set sponsor prop, PROJECT_SPONSOR, CDK_ENV_REPO, or PROJECT_REPO, or pass `ecr: false`");
3344
+ }
3345
+ this._role.addToPolicy(new PolicyStatement({
3346
+ actions: ["ecr:GetAuthorizationToken"],
3347
+ effect: Effect.ALLOW,
3348
+ resources: ["*"],
3349
+ }));
3350
+ this._role.addToPolicy(new PolicyStatement({
3351
+ actions: ECR_PUSH_ACTIONS,
3352
+ effect: Effect.ALLOW,
3353
+ resources: [`arn:aws:ecr:*:${accountId}:repository/${sponsor}-*`],
3354
+ }));
3355
+ }
3326
3356
  // Export the ARN of the role
3327
3357
  if (output !== false) {
3328
3358
  const outputId = typeof output === "string" ? output : "GitHubActionsRoleArn";