@mesh-tech/mesh-cli 0.35.1 → 0.35.2
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/bin/mesh.js +90 -18
- package/dist/bin/mesh.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/src/commands/temporal.js +90 -18
- package/dist/src/commands/temporal.js.map +1 -1
- package/dist/src/utils/aws-auth.d.ts +22 -1
- package/dist/src/utils/aws-auth.js +96 -18
- package/fragments/base/index.ts.hbs +10 -3
- package/fragments/service/api/package.json.hbs +1 -3
- package/fragments/service/api/src/index.ts.hbs +11 -3
- package/package.json +2 -2
- package/templates/api-auth/api/package.json.hbs +1 -0
- package/templates/api-auth/api/src/index.ts.hbs +11 -3
- package/templates/api-auth/index.ts.hbs +3 -0
- package/templates/api-role-gating/api/package.json.hbs +1 -0
- package/templates/api-role-gating/api/src/main.ts.hbs +7 -1
- package/templates/api-role-gating/index.ts.hbs +3 -0
- package/templates/external-service/api/src/index.ts.hbs +11 -3
- package/templates/external-service/index.ts.hbs +3 -0
- package/templates/workflow/api/src/index.ts.hbs +11 -3
- package/templates/workflow/index.ts.hbs +3 -0
package/dist/bin/mesh.js
CHANGED
|
@@ -5710,14 +5710,69 @@ function toEnv(credentials) {
|
|
|
5710
5710
|
AWS_SESSION_TOKEN: SessionToken
|
|
5711
5711
|
};
|
|
5712
5712
|
}
|
|
5713
|
-
function
|
|
5714
|
-
|
|
5715
|
-
const message = err.message ?? "";
|
|
5716
|
-
return message.includes("MaxSessionDuration") || message.includes("DurationSeconds");
|
|
5713
|
+
function isRoleChainedCaller(callerArn) {
|
|
5714
|
+
return !!callerArn && /^arn:aws[a-z-]*:sts::\d+:assumed-role\//.test(callerArn);
|
|
5717
5715
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5716
|
+
function stsErrorDetail(err) {
|
|
5717
|
+
if (!err || typeof err !== "object") return { text: String(err) };
|
|
5718
|
+
const e = err;
|
|
5719
|
+
const str = (v) => typeof v === "string" && v ? v : void 0;
|
|
5720
|
+
const name = str(e.name);
|
|
5721
|
+
const typeCode = str(str(e.__type)?.split("#").pop());
|
|
5722
|
+
const code = str(e.Code) ?? typeCode ?? str(e.Error?.Code) ?? (name && name !== "Error" ? name : void 0);
|
|
5723
|
+
const text = str(e.Error?.Message) ?? str(e.Message) ?? str(e.message) ?? code ?? String(err);
|
|
5724
|
+
return { code, text };
|
|
5725
|
+
}
|
|
5726
|
+
function isSessionDurationError(err) {
|
|
5727
|
+
if (!err || typeof err !== "object") return false;
|
|
5728
|
+
const { code, text } = stsErrorDetail(err);
|
|
5729
|
+
if (code !== void 0 && code !== "ValidationError") return false;
|
|
5730
|
+
return /DurationSeconds|MaxSessionDuration|role chaining/i.test(text);
|
|
5731
|
+
}
|
|
5732
|
+
function formatDuration(seconds) {
|
|
5733
|
+
return seconds % 3600 === 0 ? `${seconds / 3600}h` : `${seconds}s`;
|
|
5734
|
+
}
|
|
5735
|
+
function describeAssumeRoleFailure(opts) {
|
|
5736
|
+
const reason = opts.code && opts.code !== opts.text ? `${opts.code}: ${opts.text}` : opts.text;
|
|
5737
|
+
const lines = [
|
|
5738
|
+
`AssumeRole failed for ${opts.roleArn} \u2014 requested a ${formatDuration(opts.durationSeconds)} session (DurationSeconds=${opts.durationSeconds}): ${reason}`
|
|
5739
|
+
];
|
|
5740
|
+
if (opts.callerArn) lines.push(` Caller: ${opts.callerArn}`);
|
|
5741
|
+
const zitadel = `mesh login ${opts.loginContext ?? "<platform>.<env>"}`;
|
|
5742
|
+
if (isExpiredAwsTokenMessage(`${opts.code ?? ""} ${opts.text}`)) {
|
|
5743
|
+
lines.push(` Your AWS SSO session looks expired or missing \u2014 refresh with: ${SSO_LOGIN_FIX}`);
|
|
5744
|
+
lines.push(` Or assume the role via Zitadel instead: ${zitadel}`);
|
|
5745
|
+
} else if (opts.code === "AccessDenied" || /not authorized/i.test(opts.text)) {
|
|
5746
|
+
lines.push(" The role does not trust this AWS identity. Assume it via Zitadel instead:");
|
|
5747
|
+
lines.push(` ${zitadel}`);
|
|
5748
|
+
lines.push(" or switch to an AWS profile the role's trust policy allows.");
|
|
5749
|
+
} else if (isSessionDurationError({ Code: opts.code, message: opts.text })) {
|
|
5750
|
+
lines.push(
|
|
5751
|
+
` The role refused even a ${formatDuration(ROLE_CHAINING_MAX_SESSION_SECONDS)} session. Check its MaxSessionDuration, or assume it via Zitadel instead:`
|
|
5752
|
+
);
|
|
5753
|
+
lines.push(` ${zitadel}`);
|
|
5754
|
+
} else {
|
|
5755
|
+
lines.push(` Try assuming the role via Zitadel: ${zitadel}`);
|
|
5756
|
+
lines.push(` or refresh the AWS session: ${SSO_LOGIN_FIX}`);
|
|
5757
|
+
}
|
|
5758
|
+
return lines.join("\n");
|
|
5759
|
+
}
|
|
5760
|
+
async function assumeRole(roleArn, sessionName = "mesh-cli", durationSeconds = DEFAULT_ASSUME_ROLE_SECONDS, options = {}) {
|
|
5761
|
+
const sts = options.sts ?? newStsClient();
|
|
5762
|
+
let callerArn;
|
|
5763
|
+
try {
|
|
5764
|
+
callerArn = (await sts.send(new GetCallerIdentityCommand({}))).Arn;
|
|
5765
|
+
} catch {
|
|
5766
|
+
}
|
|
5767
|
+
let requested = durationSeconds;
|
|
5768
|
+
if (isRoleChainedCaller(callerArn) && requested > ROLE_CHAINING_MAX_SESSION_SECONDS) {
|
|
5769
|
+
requested = ROLE_CHAINING_MAX_SESSION_SECONDS;
|
|
5770
|
+
logInfo(
|
|
5771
|
+
`Current AWS identity is an assumed-role session \u2014 requesting a ${formatDuration(requested)} session (role chaining caps AssumeRole at one hour)`
|
|
5772
|
+
);
|
|
5773
|
+
}
|
|
5774
|
+
const attempts = requested > ROLE_CHAINING_MAX_SESSION_SECONDS ? [requested, ROLE_CHAINING_MAX_SESSION_SECONDS] : [requested];
|
|
5775
|
+
for (const [i, duration] of attempts.entries()) {
|
|
5721
5776
|
try {
|
|
5722
5777
|
const resp = await sts.send(
|
|
5723
5778
|
new AssumeRoleCommand({
|
|
@@ -5729,14 +5784,25 @@ async function assumeRole(roleArn, sessionName = "mesh-cli", durationSeconds = 4
|
|
|
5729
5784
|
if (!resp.Credentials) return null;
|
|
5730
5785
|
return toEnv(resp.Credentials);
|
|
5731
5786
|
} catch (err) {
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
return null;
|
|
5787
|
+
const isLast = i === attempts.length - 1;
|
|
5788
|
+
if (!isLast && isSessionDurationError(err)) {
|
|
5789
|
+
logInfo(
|
|
5790
|
+
`STS refused a ${formatDuration(duration)} session for ${roleArn} \u2014 retrying with ${formatDuration(ROLE_CHAINING_MAX_SESSION_SECONDS)}`
|
|
5791
|
+
);
|
|
5792
|
+
continue;
|
|
5739
5793
|
}
|
|
5794
|
+
const { code, text } = stsErrorDetail(err);
|
|
5795
|
+
logWarn(
|
|
5796
|
+
describeAssumeRoleFailure({
|
|
5797
|
+
roleArn,
|
|
5798
|
+
durationSeconds: duration,
|
|
5799
|
+
code,
|
|
5800
|
+
text,
|
|
5801
|
+
callerArn,
|
|
5802
|
+
loginContext: options.loginContext
|
|
5803
|
+
})
|
|
5804
|
+
);
|
|
5805
|
+
return null;
|
|
5740
5806
|
}
|
|
5741
5807
|
}
|
|
5742
5808
|
return null;
|
|
@@ -5766,9 +5832,10 @@ async function assumeRoleCredentials(roleArn, idToken, sessionName, durationSeco
|
|
|
5766
5832
|
Expiration: resp.Credentials.Expiration.toISOString()
|
|
5767
5833
|
};
|
|
5768
5834
|
} catch (err) {
|
|
5769
|
-
if (!
|
|
5835
|
+
if (!isSessionDurationError(err) || duration === ROLE_CHAINING_MAX_SESSION_SECONDS) {
|
|
5836
|
+
const { code, text } = stsErrorDetail(err);
|
|
5770
5837
|
logWarn(
|
|
5771
|
-
`AssumeRoleWithWebIdentity failed: ${
|
|
5838
|
+
`AssumeRoleWithWebIdentity failed: ${code && code !== text ? `${code}: ${text}` : text}`
|
|
5772
5839
|
);
|
|
5773
5840
|
return null;
|
|
5774
5841
|
}
|
|
@@ -5884,7 +5951,9 @@ async function resolveAwsCredentials(roleArn, appRoot, stack) {
|
|
|
5884
5951
|
}
|
|
5885
5952
|
}
|
|
5886
5953
|
logInfo(`Assuming ${roleName} via AWS SSO`);
|
|
5887
|
-
const creds = await assumeRole(roleArn, "mesh-cli"
|
|
5954
|
+
const creds = await assumeRole(roleArn, "mesh-cli", DEFAULT_ASSUME_ROLE_SECONDS, {
|
|
5955
|
+
loginContext: platformContext ?? void 0
|
|
5956
|
+
});
|
|
5888
5957
|
if (creds) {
|
|
5889
5958
|
logSuccess(`Assumed ${roleName}`);
|
|
5890
5959
|
return { env: creds, method: "sso" };
|
|
@@ -5903,7 +5972,7 @@ async function resolveAwsCredentials(roleArn, appRoot, stack) {
|
|
|
5903
5972
|
}
|
|
5904
5973
|
return null;
|
|
5905
5974
|
}
|
|
5906
|
-
var DEFAULT_REGION, MANAGED_START_PREFIX, MANAGED_START, MANAGED_END;
|
|
5975
|
+
var DEFAULT_REGION, MANAGED_START_PREFIX, MANAGED_START, MANAGED_END, ROLE_CHAINING_MAX_SESSION_SECONDS, DEFAULT_ASSUME_ROLE_SECONDS;
|
|
5907
5976
|
var init_aws_auth = __esm({
|
|
5908
5977
|
"packages/mesh-cli/src/utils/aws-auth.ts"() {
|
|
5909
5978
|
"use strict";
|
|
@@ -5916,6 +5985,8 @@ var init_aws_auth = __esm({
|
|
|
5916
5985
|
MANAGED_START_PREFIX = `# >>> mesh-cli managed profile `;
|
|
5917
5986
|
MANAGED_START = (context) => `${MANAGED_START_PREFIX}${context} >>>`;
|
|
5918
5987
|
MANAGED_END = `# <<< mesh-cli managed <<<`;
|
|
5988
|
+
ROLE_CHAINING_MAX_SESSION_SECONDS = 3600;
|
|
5989
|
+
DEFAULT_ASSUME_ROLE_SECONDS = 43200;
|
|
5919
5990
|
}
|
|
5920
5991
|
});
|
|
5921
5992
|
|
|
@@ -7037,6 +7108,7 @@ var init_src = __esm({
|
|
|
7037
7108
|
name: z.string().min(1),
|
|
7038
7109
|
kind: apiSurfaceKindSchema.optional(),
|
|
7039
7110
|
provider: z.string().optional(),
|
|
7111
|
+
externalService: z.string().min(1).optional(),
|
|
7040
7112
|
version: z.string().optional(),
|
|
7041
7113
|
title: z.string().optional(),
|
|
7042
7114
|
description: z.string().optional(),
|