From 48e7e5099712fa32f84e084ae587312fb70ed614 Mon Sep 17 00:00:00 2001 From: Dima Birenbaum Date: Tue, 17 Feb 2026 20:07:36 +0200 Subject: [PATCH 1/4] feat(telemetry): add SubscriptionId and TenantId passthrough for MSDO CLI AB#36805549 --- CLAUDE.md | 23 +++++++++++++++++++++++ action.yml | 4 ++++ lib/msdo.js | 8 ++++++++ src/msdo.ts | 10 ++++++++++ 4 files changed, 45 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..092de24 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,23 @@ +# CLAUDE.md - Development Guidelines + +## Core Principles (Karpathy-style) + +### 1. Think Before Coding +State assumptions explicitly. If uncertain, ask. Surface confusion rather than proceeding with silent interpretations. + +### 2. Simplicity First +Minimum code that solves the problem. Nothing speculative. No unrequested features, premature abstractions, or unnecessary error handling. + +### 3. Surgical Changes +Touch only what you must. Clean up only your own mess. Preserve existing style. Don't refactor unrelated code. + +### 4. Goal-Driven Execution +Define success criteria. Loop until verified. Transform requirements into testable goals with clear verification steps. + +## Project Conventions +- Task under PBI == PR (each ADO task maps to exactly one pull request) +- ADO org: https://dev.azure.com/msazure, project: One +- Area path: One\Rome\ShiftLeft\DevSec\CodeSec +- Build: `npm run build` (uses gulp) +- Test: `npm test` +- TypeScript compiles to `lib/` directory diff --git a/action.yml b/action.yml index 9bf8334..ed76e53 100644 --- a/action.yml +++ b/action.yml @@ -20,6 +20,10 @@ inputs: description: A comma separated list of analyzer to run. Example bandit, binskim, container-mapping, eslint, templateanalyzer, terrascan, trivy. includeTools: description: Deprecated + subscriptionId: + description: The Azure Subscription ID to include in MSDO CLI telemetry for correlation with Defender for Cloud. + tenantId: + description: The Azure Tenant ID to include in MSDO CLI telemetry for correlation with Defender for Cloud. existingFilename: description: A SARIF filename that already exists. If it does, then the normal run will not take place and the file will instead be uploaded to MSDO backend. outputs: diff --git a/lib/msdo.js b/lib/msdo.js index e15b453..7ee63ec 100644 --- a/lib/msdo.js +++ b/lib/msdo.js @@ -112,6 +112,14 @@ class MicrosoftSecurityDevOps { } args.push('--github'); } + let subscriptionId = core.getInput('subscriptionId'); + if (!common.isNullOrWhiteSpace(subscriptionId)) { + process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); + } + let tenantId = core.getInput('tenantId'); + if (!common.isNullOrWhiteSpace(tenantId)) { + process.env.MSDO_TENANTID = tenantId.trim(); + } yield client.run(args, 'microsoft/security-devops-action'); }); } diff --git a/src/msdo.ts b/src/msdo.ts index c95399c..31b43bc 100644 --- a/src/msdo.ts +++ b/src/msdo.ts @@ -97,6 +97,16 @@ export class MicrosoftSecurityDevOps implements IMicrosoftSecurityDevOps { args.push('--github'); } + let subscriptionId: string = core.getInput('subscriptionId'); + if (!common.isNullOrWhiteSpace(subscriptionId)) { + process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); + } + + let tenantId: string = core.getInput('tenantId'); + if (!common.isNullOrWhiteSpace(tenantId)) { + process.env.MSDO_TENANTID = tenantId.trim(); + } + await client.run(args, 'microsoft/security-devops-action'); } } \ No newline at end of file From 9c235c643537a6be30e08db3210b8502ea62764d Mon Sep 17 00:00:00 2001 From: Dima Birenbaum Date: Tue, 17 Feb 2026 20:28:32 +0200 Subject: [PATCH 2/4] fix(telemetry): also set MSDO_AGENTLESS_* env vars for backward compat AB#36805549 --- lib/msdo.js | 2 ++ src/msdo.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/msdo.js b/lib/msdo.js index 7ee63ec..8d19754 100644 --- a/lib/msdo.js +++ b/lib/msdo.js @@ -115,10 +115,12 @@ class MicrosoftSecurityDevOps { let subscriptionId = core.getInput('subscriptionId'); if (!common.isNullOrWhiteSpace(subscriptionId)) { process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); + process.env.MSDO_AGENTLESS_SUBSCRIPTION_ID = subscriptionId.trim(); } let tenantId = core.getInput('tenantId'); if (!common.isNullOrWhiteSpace(tenantId)) { process.env.MSDO_TENANTID = tenantId.trim(); + process.env.MSDO_AGENTLESS_TENANT_ID = tenantId.trim(); } yield client.run(args, 'microsoft/security-devops-action'); }); diff --git a/src/msdo.ts b/src/msdo.ts index 31b43bc..6a15a20 100644 --- a/src/msdo.ts +++ b/src/msdo.ts @@ -100,11 +100,13 @@ export class MicrosoftSecurityDevOps implements IMicrosoftSecurityDevOps { let subscriptionId: string = core.getInput('subscriptionId'); if (!common.isNullOrWhiteSpace(subscriptionId)) { process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); + process.env.MSDO_AGENTLESS_SUBSCRIPTION_ID = subscriptionId.trim(); } let tenantId: string = core.getInput('tenantId'); if (!common.isNullOrWhiteSpace(tenantId)) { process.env.MSDO_TENANTID = tenantId.trim(); + process.env.MSDO_AGENTLESS_TENANT_ID = tenantId.trim(); } await client.run(args, 'microsoft/security-devops-action'); From 8fa55d9f6cd37138f296d6360be3c5168b1f19b0 Mon Sep 17 00:00:00 2001 From: Dima Birenbaum Date: Tue, 17 Feb 2026 20:40:00 +0200 Subject: [PATCH 3/4] chore: remove CLAUDE.md from feature PR --- CLAUDE.md | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 092de24..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,23 +0,0 @@ -# CLAUDE.md - Development Guidelines - -## Core Principles (Karpathy-style) - -### 1. Think Before Coding -State assumptions explicitly. If uncertain, ask. Surface confusion rather than proceeding with silent interpretations. - -### 2. Simplicity First -Minimum code that solves the problem. Nothing speculative. No unrequested features, premature abstractions, or unnecessary error handling. - -### 3. Surgical Changes -Touch only what you must. Clean up only your own mess. Preserve existing style. Don't refactor unrelated code. - -### 4. Goal-Driven Execution -Define success criteria. Loop until verified. Transform requirements into testable goals with clear verification steps. - -## Project Conventions -- Task under PBI == PR (each ADO task maps to exactly one pull request) -- ADO org: https://dev.azure.com/msazure, project: One -- Area path: One\Rome\ShiftLeft\DevSec\CodeSec -- Build: `npm run build` (uses gulp) -- Test: `npm test` -- TypeScript compiles to `lib/` directory From 502ff6cd6f9f6f72e254ee572e486da0d69e6c77 Mon Sep 17 00:00:00 2001 From: Dima Birenbaum Date: Tue, 17 Feb 2026 20:47:48 +0200 Subject: [PATCH 4/4] feat(telemetry): auto-infer SubscriptionId/TenantId from Azure CLI and env vars AB#36805549 --- lib/msdo.js | 28 +++++++++++++++++++++++++++- src/msdo.ts | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/msdo.js b/lib/msdo.js index 8d19754..f6374b4 100644 --- a/lib/msdo.js +++ b/lib/msdo.js @@ -34,6 +34,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", { value: true }); exports.MicrosoftSecurityDevOps = void 0; const core = __importStar(require("@actions/core")); +const exec = __importStar(require("@actions/exec")); const msdo_helpers_1 = require("./msdo-helpers"); const client = __importStar(require("@microsoft/security-devops-actions-toolkit/msdo-client")); const common = __importStar(require("@microsoft/security-devops-actions-toolkit/msdo-common")); @@ -113,11 +114,36 @@ class MicrosoftSecurityDevOps { args.push('--github'); } let subscriptionId = core.getInput('subscriptionId'); + let tenantId = core.getInput('tenantId'); + if (common.isNullOrWhiteSpace(subscriptionId)) { + subscriptionId = process.env.AZURE_SUBSCRIPTION_ID || ''; + } + if (common.isNullOrWhiteSpace(tenantId)) { + tenantId = process.env.AZURE_TENANT_ID || ''; + } + if (common.isNullOrWhiteSpace(subscriptionId) || common.isNullOrWhiteSpace(tenantId)) { + try { + let azOutput = yield exec.getExecOutput('az account show --query "{tenantId:tenantId,id:id}" -o json', [], { silent: true, ignoreReturnCode: true }); + if (azOutput.exitCode === 0) { + let account = JSON.parse(azOutput.stdout.trim()); + if (common.isNullOrWhiteSpace(subscriptionId) && account.id) { + subscriptionId = account.id; + core.debug(`Auto-inferred subscriptionId from Azure CLI`); + } + if (common.isNullOrWhiteSpace(tenantId) && account.tenantId) { + tenantId = account.tenantId; + core.debug(`Auto-inferred tenantId from Azure CLI`); + } + } + } + catch (_a) { + core.debug('Azure CLI not available for auto-inference of subscriptionId/tenantId'); + } + } if (!common.isNullOrWhiteSpace(subscriptionId)) { process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); process.env.MSDO_AGENTLESS_SUBSCRIPTION_ID = subscriptionId.trim(); } - let tenantId = core.getInput('tenantId'); if (!common.isNullOrWhiteSpace(tenantId)) { process.env.MSDO_TENANTID = tenantId.trim(); process.env.MSDO_AGENTLESS_TENANT_ID = tenantId.trim(); diff --git a/src/msdo.ts b/src/msdo.ts index 6a15a20..56ca14f 100644 --- a/src/msdo.ts +++ b/src/msdo.ts @@ -1,4 +1,5 @@ import * as core from '@actions/core'; +import * as exec from '@actions/exec'; import { IMicrosoftSecurityDevOps } from './msdo-interface'; import { Tools } from './msdo-helpers'; import * as client from '@microsoft/security-devops-actions-toolkit/msdo-client'; @@ -98,12 +99,45 @@ export class MicrosoftSecurityDevOps implements IMicrosoftSecurityDevOps { } let subscriptionId: string = core.getInput('subscriptionId'); + let tenantId: string = core.getInput('tenantId'); + + // Auto-infer from common Azure env vars if not explicitly provided + if (common.isNullOrWhiteSpace(subscriptionId)) { + subscriptionId = process.env.AZURE_SUBSCRIPTION_ID || ''; + } + if (common.isNullOrWhiteSpace(tenantId)) { + tenantId = process.env.AZURE_TENANT_ID || ''; + } + + // Auto-infer from Azure CLI if still not available (e.g., after azure/login) + if (common.isNullOrWhiteSpace(subscriptionId) || common.isNullOrWhiteSpace(tenantId)) { + try { + let azOutput = await exec.getExecOutput( + 'az account show --query "{tenantId:tenantId,id:id}" -o json', + [], + { silent: true, ignoreReturnCode: true } + ); + if (azOutput.exitCode === 0) { + let account = JSON.parse(azOutput.stdout.trim()); + if (common.isNullOrWhiteSpace(subscriptionId) && account.id) { + subscriptionId = account.id; + core.debug(`Auto-inferred subscriptionId from Azure CLI`); + } + if (common.isNullOrWhiteSpace(tenantId) && account.tenantId) { + tenantId = account.tenantId; + core.debug(`Auto-inferred tenantId from Azure CLI`); + } + } + } catch { + core.debug('Azure CLI not available for auto-inference of subscriptionId/tenantId'); + } + } + if (!common.isNullOrWhiteSpace(subscriptionId)) { process.env.MSDO_SUBSCRIPTIONID = subscriptionId.trim(); process.env.MSDO_AGENTLESS_SUBSCRIPTION_ID = subscriptionId.trim(); } - let tenantId: string = core.getInput('tenantId'); if (!common.isNullOrWhiteSpace(tenantId)) { process.env.MSDO_TENANTID = tenantId.trim(); process.env.MSDO_AGENTLESS_TENANT_ID = tenantId.trim();