@peterhauge/apiops-cli 0.1.3-alpha.0
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/LICENSE.md +21 -0
- package/README.md +135 -0
- package/dist/cli/extract-command.d.ts +12 -0
- package/dist/cli/extract-command.d.ts.map +1 -0
- package/dist/cli/extract-command.js +157 -0
- package/dist/cli/extract-command.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +74 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-command.d.ts +11 -0
- package/dist/cli/init-command.d.ts.map +1 -0
- package/dist/cli/init-command.js +87 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/publish-command.d.ts +12 -0
- package/dist/cli/publish-command.d.ts.map +1 -0
- package/dist/cli/publish-command.js +159 -0
- package/dist/cli/publish-command.js.map +1 -0
- package/dist/clients/apim-client.d.ts +110 -0
- package/dist/clients/apim-client.d.ts.map +1 -0
- package/dist/clients/apim-client.js +586 -0
- package/dist/clients/apim-client.js.map +1 -0
- package/dist/clients/artifact-store.d.ts +23 -0
- package/dist/clients/artifact-store.d.ts.map +1 -0
- package/dist/clients/artifact-store.js +188 -0
- package/dist/clients/artifact-store.js.map +1 -0
- package/dist/clients/iapim-client.d.ts +52 -0
- package/dist/clients/iapim-client.d.ts.map +1 -0
- package/dist/clients/iapim-client.js +6 -0
- package/dist/clients/iapim-client.js.map +1 -0
- package/dist/clients/iartifact-store.d.ts +50 -0
- package/dist/clients/iartifact-store.d.ts.map +1 -0
- package/dist/clients/iartifact-store.js +6 -0
- package/dist/clients/iartifact-store.js.map +1 -0
- package/dist/lib/auto-generated.d.ts +27 -0
- package/dist/lib/auto-generated.d.ts.map +1 -0
- package/dist/lib/auto-generated.js +34 -0
- package/dist/lib/auto-generated.js.map +1 -0
- package/dist/lib/cloud-config.d.ts +29 -0
- package/dist/lib/cloud-config.d.ts.map +1 -0
- package/dist/lib/cloud-config.js +60 -0
- package/dist/lib/cloud-config.js.map +1 -0
- package/dist/lib/config-loader.d.ts +21 -0
- package/dist/lib/config-loader.d.ts.map +1 -0
- package/dist/lib/config-loader.js +131 -0
- package/dist/lib/config-loader.js.map +1 -0
- package/dist/lib/dependency-graph.d.ts +43 -0
- package/dist/lib/dependency-graph.d.ts.map +1 -0
- package/dist/lib/dependency-graph.js +163 -0
- package/dist/lib/dependency-graph.js.map +1 -0
- package/dist/lib/exit-codes.d.ts +27 -0
- package/dist/lib/exit-codes.d.ts.map +1 -0
- package/dist/lib/exit-codes.js +33 -0
- package/dist/lib/exit-codes.js.map +1 -0
- package/dist/lib/logger.d.ts +39 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +128 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/parallel-runner.d.ts +38 -0
- package/dist/lib/parallel-runner.d.ts.map +1 -0
- package/dist/lib/parallel-runner.js +70 -0
- package/dist/lib/parallel-runner.js.map +1 -0
- package/dist/lib/resource-path.d.ts +205 -0
- package/dist/lib/resource-path.d.ts.map +1 -0
- package/dist/lib/resource-path.js +401 -0
- package/dist/lib/resource-path.js.map +1 -0
- package/dist/lib/resource-uri.d.ts +40 -0
- package/dist/lib/resource-uri.d.ts.map +1 -0
- package/dist/lib/resource-uri.js +86 -0
- package/dist/lib/resource-uri.js.map +1 -0
- package/dist/lib/user-agent.d.ts +2 -0
- package/dist/lib/user-agent.d.ts.map +1 -0
- package/dist/lib/user-agent.js +5 -0
- package/dist/lib/user-agent.js.map +1 -0
- package/dist/models/config.d.ts +83 -0
- package/dist/models/config.d.ts.map +1 -0
- package/dist/models/config.js +6 -0
- package/dist/models/config.js.map +1 -0
- package/dist/models/resource-types.d.ts +66 -0
- package/dist/models/resource-types.d.ts.map +1 -0
- package/dist/models/resource-types.js +243 -0
- package/dist/models/resource-types.js.map +1 -0
- package/dist/models/types.d.ts +47 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +6 -0
- package/dist/models/types.js.map +1 -0
- package/dist/services/api-extractor.d.ts +36 -0
- package/dist/services/api-extractor.d.ts.map +1 -0
- package/dist/services/api-extractor.js +319 -0
- package/dist/services/api-extractor.js.map +1 -0
- package/dist/services/api-publisher.d.ts +18 -0
- package/dist/services/api-publisher.d.ts.map +1 -0
- package/dist/services/api-publisher.js +290 -0
- package/dist/services/api-publisher.js.map +1 -0
- package/dist/services/delete-unmatched-service.d.ts +17 -0
- package/dist/services/delete-unmatched-service.d.ts.map +1 -0
- package/dist/services/delete-unmatched-service.js +143 -0
- package/dist/services/delete-unmatched-service.js.map +1 -0
- package/dist/services/dry-run-reporter.d.ts +30 -0
- package/dist/services/dry-run-reporter.d.ts.map +1 -0
- package/dist/services/dry-run-reporter.js +111 -0
- package/dist/services/dry-run-reporter.js.map +1 -0
- package/dist/services/extract-service.d.ts +47 -0
- package/dist/services/extract-service.d.ts.map +1 -0
- package/dist/services/extract-service.js +374 -0
- package/dist/services/extract-service.js.map +1 -0
- package/dist/services/filter-service.d.ts +29 -0
- package/dist/services/filter-service.d.ts.map +1 -0
- package/dist/services/filter-service.js +143 -0
- package/dist/services/filter-service.js.map +1 -0
- package/dist/services/git-diff-service.d.ts +23 -0
- package/dist/services/git-diff-service.d.ts.map +1 -0
- package/dist/services/git-diff-service.js +135 -0
- package/dist/services/git-diff-service.js.map +1 -0
- package/dist/services/identity-guide-service.d.ts +11 -0
- package/dist/services/identity-guide-service.d.ts.map +1 -0
- package/dist/services/identity-guide-service.js +227 -0
- package/dist/services/identity-guide-service.js.map +1 -0
- package/dist/services/init-service.d.ts +16 -0
- package/dist/services/init-service.d.ts.map +1 -0
- package/dist/services/init-service.js +304 -0
- package/dist/services/init-service.js.map +1 -0
- package/dist/services/keyvault-checker.d.ts +58 -0
- package/dist/services/keyvault-checker.d.ts.map +1 -0
- package/dist/services/keyvault-checker.js +390 -0
- package/dist/services/keyvault-checker.js.map +1 -0
- package/dist/services/override-merger.d.ts +20 -0
- package/dist/services/override-merger.d.ts.map +1 -0
- package/dist/services/override-merger.js +102 -0
- package/dist/services/override-merger.js.map +1 -0
- package/dist/services/product-extractor.d.ts +26 -0
- package/dist/services/product-extractor.d.ts.map +1 -0
- package/dist/services/product-extractor.js +141 -0
- package/dist/services/product-extractor.js.map +1 -0
- package/dist/services/product-publisher.d.ts +15 -0
- package/dist/services/product-publisher.d.ts.map +1 -0
- package/dist/services/product-publisher.js +113 -0
- package/dist/services/product-publisher.js.map +1 -0
- package/dist/services/prompt-service.d.ts +13 -0
- package/dist/services/prompt-service.d.ts.map +1 -0
- package/dist/services/prompt-service.js +69 -0
- package/dist/services/prompt-service.js.map +1 -0
- package/dist/services/publish-service.d.ts +31 -0
- package/dist/services/publish-service.d.ts.map +1 -0
- package/dist/services/publish-service.js +445 -0
- package/dist/services/publish-service.js.map +1 -0
- package/dist/services/resource-extractor.d.ts +52 -0
- package/dist/services/resource-extractor.d.ts.map +1 -0
- package/dist/services/resource-extractor.js +168 -0
- package/dist/services/resource-extractor.js.map +1 -0
- package/dist/services/resource-publisher.d.ts +23 -0
- package/dist/services/resource-publisher.d.ts.map +1 -0
- package/dist/services/resource-publisher.js +349 -0
- package/dist/services/resource-publisher.js.map +1 -0
- package/dist/services/secret-redactor.d.ts +20 -0
- package/dist/services/secret-redactor.d.ts.map +1 -0
- package/dist/services/secret-redactor.js +45 -0
- package/dist/services/secret-redactor.js.map +1 -0
- package/dist/services/transitive-resolver.d.ts +45 -0
- package/dist/services/transitive-resolver.d.ts.map +1 -0
- package/dist/services/transitive-resolver.js +177 -0
- package/dist/services/transitive-resolver.js.map +1 -0
- package/dist/services/workspace-extractor.d.ts +34 -0
- package/dist/services/workspace-extractor.d.ts.map +1 -0
- package/dist/services/workspace-extractor.js +120 -0
- package/dist/services/workspace-extractor.js.map +1 -0
- package/dist/templates/azure-devops/extract-pipeline.d.ts +9 -0
- package/dist/templates/azure-devops/extract-pipeline.d.ts.map +1 -0
- package/dist/templates/azure-devops/extract-pipeline.js +95 -0
- package/dist/templates/azure-devops/extract-pipeline.js.map +1 -0
- package/dist/templates/azure-devops/publish-pipeline.d.ts +10 -0
- package/dist/templates/azure-devops/publish-pipeline.d.ts.map +1 -0
- package/dist/templates/azure-devops/publish-pipeline.js +100 -0
- package/dist/templates/azure-devops/publish-pipeline.js.map +1 -0
- package/dist/templates/configs/filter-config.d.ts +6 -0
- package/dist/templates/configs/filter-config.d.ts.map +1 -0
- package/dist/templates/configs/filter-config.js +51 -0
- package/dist/templates/configs/filter-config.js.map +1 -0
- package/dist/templates/configs/override-config.d.ts +6 -0
- package/dist/templates/configs/override-config.d.ts.map +1 -0
- package/dist/templates/configs/override-config.js +45 -0
- package/dist/templates/configs/override-config.js.map +1 -0
- package/dist/templates/configs/package-json.d.ts +10 -0
- package/dist/templates/configs/package-json.d.ts.map +1 -0
- package/dist/templates/configs/package-json.js +19 -0
- package/dist/templates/configs/package-json.js.map +1 -0
- package/dist/templates/copilot/identity-setup-prompt.d.ts +13 -0
- package/dist/templates/copilot/identity-setup-prompt.d.ts.map +1 -0
- package/dist/templates/copilot/identity-setup-prompt.js +279 -0
- package/dist/templates/copilot/identity-setup-prompt.js.map +1 -0
- package/dist/templates/github-actions/extract-workflow.d.ts +9 -0
- package/dist/templates/github-actions/extract-workflow.d.ts.map +1 -0
- package/dist/templates/github-actions/extract-workflow.js +126 -0
- package/dist/templates/github-actions/extract-workflow.js.map +1 -0
- package/dist/templates/github-actions/publish-workflow.d.ts +10 -0
- package/dist/templates/github-actions/publish-workflow.d.ts.map +1 -0
- package/dist/templates/github-actions/publish-workflow.js +105 -0
- package/dist/templates/github-actions/publish-workflow.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T036: Git diff service
|
|
3
|
+
* Compute changed resource artifacts between commits using simple-git.
|
|
4
|
+
* Maps file paths to ResourceDescriptors for incremental publish.
|
|
5
|
+
*/
|
|
6
|
+
import { simpleGit } from 'simple-git';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { parseArtifactPath } from '../lib/resource-path.js';
|
|
9
|
+
import { logger } from '../lib/logger.js';
|
|
10
|
+
/**
|
|
11
|
+
* Compute which resource artifacts changed between commitId~1 and commitId.
|
|
12
|
+
* Uses simple-git. Maps file paths to ResourceDescriptors.
|
|
13
|
+
* Returns empty arrays if git is unavailable or path not in a repo.
|
|
14
|
+
*
|
|
15
|
+
* @param sourceDir - Root artifact directory
|
|
16
|
+
* @param commitId - Commit SHA to diff against its parent
|
|
17
|
+
* @returns Changed and deleted resource descriptors
|
|
18
|
+
*/
|
|
19
|
+
export async function computeGitDiff(sourceDir, commitId) {
|
|
20
|
+
const git = simpleGit(sourceDir);
|
|
21
|
+
try {
|
|
22
|
+
// Check if we're in a git repository
|
|
23
|
+
const isRepo = await git.checkIsRepo();
|
|
24
|
+
if (!isRepo) {
|
|
25
|
+
logger.warn('Not in a git repository; skipping incremental diff');
|
|
26
|
+
return { changedDescriptors: [], deletedDescriptors: [] };
|
|
27
|
+
}
|
|
28
|
+
// Verify the commit exists
|
|
29
|
+
try {
|
|
30
|
+
await git.revparse([commitId]);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
logger.warn(`Commit ${commitId} not found; skipping incremental diff`);
|
|
34
|
+
return { changedDescriptors: [], deletedDescriptors: [] };
|
|
35
|
+
}
|
|
36
|
+
// Check if parent commit exists (handle first commit case)
|
|
37
|
+
const parentCommit = `${commitId}~1`;
|
|
38
|
+
let hasParent = true;
|
|
39
|
+
try {
|
|
40
|
+
await git.revparse([parentCommit]);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
logger.debug(`Commit ${commitId} has no parent (first commit); treating all files as added`);
|
|
44
|
+
hasParent = false;
|
|
45
|
+
}
|
|
46
|
+
// Get diff between parent and current commit
|
|
47
|
+
// If no parent, diff against empty tree (shows all files as added)
|
|
48
|
+
const diffTarget = hasParent ? parentCommit : '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; // Git empty tree SHA
|
|
49
|
+
const diffOutput = await git.diff(['--name-status', diffTarget, commitId]);
|
|
50
|
+
return parseDiffOutput(diffOutput, sourceDir);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
logger.warn(`Git diff failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
54
|
+
return { changedDescriptors: [], deletedDescriptors: [] };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse git diff --name-status output into changed and deleted descriptors.
|
|
59
|
+
*
|
|
60
|
+
* Format: Each line is "{status}\t{filepath}"
|
|
61
|
+
* - M = modified
|
|
62
|
+
* - A = added
|
|
63
|
+
* - D = deleted
|
|
64
|
+
* - R = renamed (includes old and new paths)
|
|
65
|
+
* - C = copied
|
|
66
|
+
*
|
|
67
|
+
* @param diffOutput - Raw output from git diff --name-status
|
|
68
|
+
* @param sourceDir - Base directory for artifact paths
|
|
69
|
+
* @returns Parsed descriptors
|
|
70
|
+
*/
|
|
71
|
+
function parseDiffOutput(diffOutput, sourceDir) {
|
|
72
|
+
const changedDescriptors = [];
|
|
73
|
+
const deletedDescriptors = [];
|
|
74
|
+
const seenChanged = new Set();
|
|
75
|
+
const seenDeleted = new Set();
|
|
76
|
+
const lines = diffOutput.split('\n').filter((line) => line.trim());
|
|
77
|
+
for (const line of lines) {
|
|
78
|
+
const parts = line.split('\t');
|
|
79
|
+
if (parts.length < 2) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const status = parts[0]?.charAt(0); // Get first character (M, A, D, R, C)
|
|
83
|
+
const filePath = parts[1];
|
|
84
|
+
if (!status || !filePath) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Convert relative path to absolute for parsing
|
|
88
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
89
|
+
? filePath
|
|
90
|
+
: path.join(sourceDir, filePath);
|
|
91
|
+
const descriptor = parseArtifactPath(sourceDir, absolutePath);
|
|
92
|
+
if (!descriptor) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
// Create unique key for deduplication
|
|
96
|
+
const key = descriptorKey(descriptor);
|
|
97
|
+
if (status === 'D') {
|
|
98
|
+
// Deleted file
|
|
99
|
+
if (!seenDeleted.has(key)) {
|
|
100
|
+
deletedDescriptors.push(descriptor);
|
|
101
|
+
seenDeleted.add(key);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (status === 'M' || status === 'A' || status === 'R' || status === 'C') {
|
|
105
|
+
// Modified, added, renamed, or copied file
|
|
106
|
+
if (!seenChanged.has(key)) {
|
|
107
|
+
changedDescriptors.push(descriptor);
|
|
108
|
+
seenChanged.add(key);
|
|
109
|
+
}
|
|
110
|
+
// For renames, also parse the new path (in parts[2])
|
|
111
|
+
if (status === 'R' && parts[2]) {
|
|
112
|
+
const newPath = path.isAbsolute(parts[2])
|
|
113
|
+
? parts[2]
|
|
114
|
+
: path.join(sourceDir, parts[2]);
|
|
115
|
+
const newDescriptor = parseArtifactPath(sourceDir, newPath);
|
|
116
|
+
if (newDescriptor) {
|
|
117
|
+
const newKey = descriptorKey(newDescriptor);
|
|
118
|
+
if (!seenChanged.has(newKey)) {
|
|
119
|
+
changedDescriptors.push(newDescriptor);
|
|
120
|
+
seenChanged.add(newKey);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
logger.debug(`Git diff found ${changedDescriptors.length} changed, ${deletedDescriptors.length} deleted resources`);
|
|
127
|
+
return { changedDescriptors, deletedDescriptors };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Create a unique key for a resource descriptor to enable deduplication.
|
|
131
|
+
*/
|
|
132
|
+
function descriptorKey(descriptor) {
|
|
133
|
+
return [descriptor.type, ...descriptor.nameParts, descriptor.workspace ?? ''].join('::');
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=git-diff-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-diff-service.js","sourceRoot":"","sources":["../../src/services/git-diff-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T048: Identity setup guide generator
|
|
3
|
+
* Step-by-step instructions for service principal, RBAC, federated credentials,
|
|
4
|
+
* pipeline secrets/service connections. Optional az CLI automation per FR-021.
|
|
5
|
+
*/
|
|
6
|
+
export interface IdentityGuideService {
|
|
7
|
+
generateGitHubActionsGuide(subscriptionId: string, resourceGroup: string, environments: string[]): string;
|
|
8
|
+
generateAzureDevOpsGuide(subscriptionId: string, resourceGroup: string, environments: string[]): string;
|
|
9
|
+
}
|
|
10
|
+
export declare const identityGuideService: IdentityGuideService;
|
|
11
|
+
//# sourceMappingURL=identity-guide-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-guide-service.d.ts","sourceRoot":"","sources":["../../src/services/identity-guide-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,oBAAoB;IACnC,0BAA0B,CACxB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,MAAM,CAAC;IAEV,wBAAwB,CACtB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,MAAM,CAAC;CACX;AAwOD,eAAO,MAAM,oBAAoB,EAAE,oBAAqD,CAAC"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T048: Identity setup guide generator
|
|
3
|
+
* Step-by-step instructions for service principal, RBAC, federated credentials,
|
|
4
|
+
* pipeline secrets/service connections. Optional az CLI automation per FR-021.
|
|
5
|
+
*/
|
|
6
|
+
class IdentityGuideServiceImpl {
|
|
7
|
+
generateGitHubActionsGuide(subscriptionId, resourceGroup, environments) {
|
|
8
|
+
return `# GitHub Actions Identity Setup Guide
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
- Azure subscription: ${subscriptionId}
|
|
12
|
+
- Resource group: ${resourceGroup}
|
|
13
|
+
- GitHub repository with OIDC enabled
|
|
14
|
+
|
|
15
|
+
## Step 1: Create Service Principal
|
|
16
|
+
|
|
17
|
+
Run the following Azure CLI commands to create a service principal with federated credentials:
|
|
18
|
+
|
|
19
|
+
\`\`\`bash
|
|
20
|
+
# Set variables
|
|
21
|
+
SUBSCRIPTION_ID="${subscriptionId}"
|
|
22
|
+
RESOURCE_GROUP="${resourceGroup}"
|
|
23
|
+
APP_NAME="apiops-github-sp"
|
|
24
|
+
GITHUB_ORG="<your-github-org>"
|
|
25
|
+
GITHUB_REPO="<your-github-repo>"
|
|
26
|
+
|
|
27
|
+
# Create Azure AD Application
|
|
28
|
+
APP_ID=$(az ad app create \\
|
|
29
|
+
--display-name "$APP_NAME" \\
|
|
30
|
+
--query appId -o tsv)
|
|
31
|
+
|
|
32
|
+
# Create Service Principal
|
|
33
|
+
az ad sp create --id "$APP_ID"
|
|
34
|
+
|
|
35
|
+
# Get Service Principal Object ID
|
|
36
|
+
SP_OBJECT_ID=$(az ad sp show --id "$APP_ID" --query id -o tsv)
|
|
37
|
+
|
|
38
|
+
echo "Application (client) ID: $APP_ID"
|
|
39
|
+
echo "Service Principal Object ID: $SP_OBJECT_ID"
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
## Step 2: Assign RBAC Roles
|
|
43
|
+
|
|
44
|
+
Grant the service principal "API Management Service Contributor" role on your APIM instance:
|
|
45
|
+
|
|
46
|
+
\`\`\`bash
|
|
47
|
+
# Get APIM resource ID
|
|
48
|
+
APIM_RESOURCE_ID=$(az apim show \\
|
|
49
|
+
--resource-group "$RESOURCE_GROUP" \\
|
|
50
|
+
--name "<your-apim-service-name>" \\
|
|
51
|
+
--query id -o tsv)
|
|
52
|
+
|
|
53
|
+
# Assign role
|
|
54
|
+
az role assignment create \\
|
|
55
|
+
--assignee "$APP_ID" \\
|
|
56
|
+
--role "API Management Service Contributor" \\
|
|
57
|
+
--scope "$APIM_RESOURCE_ID"
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
## Step 3: Configure Federated Credentials
|
|
61
|
+
|
|
62
|
+
Set up OIDC federation for GitHub Actions:
|
|
63
|
+
|
|
64
|
+
\`\`\`bash
|
|
65
|
+
# For main branch deployments
|
|
66
|
+
az ad app federated-credential create \\
|
|
67
|
+
--id "$APP_ID" \\
|
|
68
|
+
--parameters '{
|
|
69
|
+
"name": "github-main-branch",
|
|
70
|
+
"issuer": "https://token.actions.githubusercontent.com",
|
|
71
|
+
"subject": "repo:'"$GITHUB_ORG"'/'"$GITHUB_REPO"':ref:refs/heads/main",
|
|
72
|
+
"audiences": ["api://AzureADTokenExchange"]
|
|
73
|
+
}'
|
|
74
|
+
|
|
75
|
+
# For environment deployments (repeat for each environment)
|
|
76
|
+
${environments.map((env) => `az ad app federated-credential create \\
|
|
77
|
+
--id "$APP_ID" \\
|
|
78
|
+
--parameters '{
|
|
79
|
+
"name": "github-env-${env}",
|
|
80
|
+
"issuer": "https://token.actions.githubusercontent.com",
|
|
81
|
+
"subject": "repo:'"$GITHUB_ORG"'/'"$GITHUB_REPO"':environment:${env}",
|
|
82
|
+
"audiences": ["api://AzureADTokenExchange"]
|
|
83
|
+
}'`).join('\n\n')}
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
## Step 4: Configure GitHub Secrets
|
|
87
|
+
|
|
88
|
+
Add the following secrets to your GitHub repository (Settings → Secrets and variables → Actions):
|
|
89
|
+
|
|
90
|
+
### Repository Secrets:
|
|
91
|
+
- \`AZURE_CLIENT_ID\`: $APP_ID (from Step 1)
|
|
92
|
+
- \`AZURE_TENANT_ID\`: Run \`az account show --query tenantId -o tsv\`
|
|
93
|
+
- \`AZURE_SUBSCRIPTION_ID\`: ${subscriptionId}
|
|
94
|
+
|
|
95
|
+
### Environment-Specific Secrets:
|
|
96
|
+
${environments.map((env) => `
|
|
97
|
+
**For ${env} environment:**
|
|
98
|
+
- \`APIM_RESOURCE_GROUP_${env.toUpperCase()}\`: Resource group for ${env}
|
|
99
|
+
- \`APIM_SERVICE_NAME_${env.toUpperCase()}\`: APIM service name for ${env}
|
|
100
|
+
`).join('\n')}
|
|
101
|
+
|
|
102
|
+
### Extract Workflow Secrets:
|
|
103
|
+
- \`APIM_RESOURCE_GROUP\`: Default resource group for extract
|
|
104
|
+
- \`APIM_SERVICE_NAME\`: Default APIM service name for extract
|
|
105
|
+
|
|
106
|
+
## Step 5: Verify Setup
|
|
107
|
+
|
|
108
|
+
Test the authentication by running a workflow manually or pushing to main branch.
|
|
109
|
+
|
|
110
|
+
## Security Notes
|
|
111
|
+
- Use GitHub Environments for production deployments with required reviewers
|
|
112
|
+
- Rotate service principal credentials periodically
|
|
113
|
+
- Review federated credential subjects regularly
|
|
114
|
+
- Use least-privilege RBAC assignments
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
generateAzureDevOpsGuide(subscriptionId, resourceGroup, environments) {
|
|
118
|
+
return `# Azure DevOps Identity Setup Guide
|
|
119
|
+
|
|
120
|
+
## Prerequisites
|
|
121
|
+
- Azure subscription: ${subscriptionId}
|
|
122
|
+
- Resource group: ${resourceGroup}
|
|
123
|
+
- Azure DevOps organization and project
|
|
124
|
+
|
|
125
|
+
## Step 1: Create Service Principal
|
|
126
|
+
|
|
127
|
+
Create a service principal for each environment or use a single shared one:
|
|
128
|
+
|
|
129
|
+
\`\`\`bash
|
|
130
|
+
# Set variables
|
|
131
|
+
SUBSCRIPTION_ID="${subscriptionId}"
|
|
132
|
+
RESOURCE_GROUP="${resourceGroup}"
|
|
133
|
+
APP_NAME="apiops-azdo-sp"
|
|
134
|
+
|
|
135
|
+
# Create Service Principal with Contributor role
|
|
136
|
+
SP_OUTPUT=$(az ad sp create-for-rbac \\
|
|
137
|
+
--name "$APP_NAME" \\
|
|
138
|
+
--role "API Management Service Contributor" \\
|
|
139
|
+
--scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP" \\
|
|
140
|
+
--sdk-auth)
|
|
141
|
+
|
|
142
|
+
echo "$SP_OUTPUT"
|
|
143
|
+
|
|
144
|
+
# Save the output - you'll need these values:
|
|
145
|
+
# - appId (client ID)
|
|
146
|
+
# - password (client secret)
|
|
147
|
+
# - tenant
|
|
148
|
+
\`\`\`
|
|
149
|
+
|
|
150
|
+
## Step 2: Create Azure Service Connections
|
|
151
|
+
|
|
152
|
+
In Azure DevOps, create service connections for Azure Resource Manager:
|
|
153
|
+
|
|
154
|
+
1. Go to Project Settings → Service connections
|
|
155
|
+
2. Click "New service connection" → "Azure Resource Manager" → "Service principal (manual)"
|
|
156
|
+
3. Fill in the details from Step 1:
|
|
157
|
+
- **Subscription ID**: ${subscriptionId}
|
|
158
|
+
- **Subscription Name**: (your subscription name)
|
|
159
|
+
- **Service Principal ID**: appId from Step 1
|
|
160
|
+
- **Service Principal Key**: password from Step 1
|
|
161
|
+
- **Tenant ID**: tenant from Step 1
|
|
162
|
+
|
|
163
|
+
${environments.map((env) => `
|
|
164
|
+
**For ${env} environment:**
|
|
165
|
+
- Connection name: \`AZURE_SERVICE_CONNECTION_${env.toUpperCase()}\`
|
|
166
|
+
- Verify: Test the connection
|
|
167
|
+
`).join('\n')}
|
|
168
|
+
|
|
169
|
+
**For extract pipeline:**
|
|
170
|
+
- Connection name: \`AZURE_SERVICE_CONNECTION\`
|
|
171
|
+
- Verify: Test the connection
|
|
172
|
+
|
|
173
|
+
## Step 3: Create Variable Groups
|
|
174
|
+
|
|
175
|
+
Create variable groups in Azure DevOps Library:
|
|
176
|
+
|
|
177
|
+
### Common Variable Group (\`apim-common\`):
|
|
178
|
+
- \`AZURE_SUBSCRIPTION_ID\`: ${subscriptionId}
|
|
179
|
+
- \`APIM_RESOURCE_GROUP\`: ${resourceGroup}
|
|
180
|
+
- \`APIM_SERVICE_NAME\`: <your-apim-service-name>
|
|
181
|
+
- \`AZURE_SERVICE_CONNECTION\`: Name from Step 2
|
|
182
|
+
|
|
183
|
+
${environments.map((env) => `
|
|
184
|
+
### ${env} Environment Variable Group (\`apim-${env}\`):
|
|
185
|
+
- \`APIM_RESOURCE_GROUP_${env.toUpperCase()}\`: Resource group for ${env}
|
|
186
|
+
- \`APIM_SERVICE_NAME_${env.toUpperCase()}\`: APIM service name for ${env}
|
|
187
|
+
- \`AZURE_SERVICE_CONNECTION_${env.toUpperCase()}\`: Service connection name for ${env}
|
|
188
|
+
`).join('\n')}
|
|
189
|
+
|
|
190
|
+
## Step 4: Configure Pipeline Permissions
|
|
191
|
+
|
|
192
|
+
1. Go to Pipelines → Library → Variable Groups
|
|
193
|
+
2. For each variable group, click "Pipeline permissions"
|
|
194
|
+
3. Allow the extract and publish pipelines to use these variable groups
|
|
195
|
+
|
|
196
|
+
## Step 5: Create Environments
|
|
197
|
+
|
|
198
|
+
Create deployment environments in Azure DevOps:
|
|
199
|
+
|
|
200
|
+
1. Go to Pipelines → Environments
|
|
201
|
+
2. Create new environment for each:
|
|
202
|
+
${environments.map((env) => ` - \`${env}\``).join('\n')}
|
|
203
|
+
3. Configure approvals and checks as needed for production environments
|
|
204
|
+
|
|
205
|
+
## Step 6: Enable Pipeline Contributions
|
|
206
|
+
|
|
207
|
+
For the extract pipeline to commit changes:
|
|
208
|
+
|
|
209
|
+
1. Go to Project Settings → Repositories → Security
|
|
210
|
+
2. Find "Build Service" account
|
|
211
|
+
3. Grant "Contribute" and "Contribute to pull requests" permissions
|
|
212
|
+
|
|
213
|
+
## Step 7: Verify Setup
|
|
214
|
+
|
|
215
|
+
Run the extract pipeline manually to verify authentication and permissions.
|
|
216
|
+
|
|
217
|
+
## Security Notes
|
|
218
|
+
- Use separate service principals for production environments
|
|
219
|
+
- Enable environment approvals for production deployments
|
|
220
|
+
- Rotate service principal secrets periodically (recommended: 90 days)
|
|
221
|
+
- Use managed identities when possible for Azure-hosted agents
|
|
222
|
+
- Review RBAC assignments regularly
|
|
223
|
+
`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
export const identityGuideService = new IdentityGuideServiceImpl();
|
|
227
|
+
//# sourceMappingURL=identity-guide-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-guide-service.js","sourceRoot":"","sources":["../../src/services/identity-guide-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH,MAAM,wBAAwB;IAC5B,0BAA0B,CACxB,cAAsB,EACtB,aAAqB,EACrB,YAAsB;QAEtB,OAAO;;;wBAGa,cAAc;oBAClB,aAAa;;;;;;;;;mBASd,cAAc;kBACf,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsD7B,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;;;0BAGF,GAAG;;oEAEuC,GAAG;;KAElE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;+BAUY,cAAc;;;EAG3C,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QACpB,GAAG;0BACe,GAAG,CAAC,WAAW,EAAE,0BAA0B,GAAG;wBAChD,GAAG,CAAC,WAAW,EAAE,6BAA6B,GAAG;CACxE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;CAeZ,CAAC;IACA,CAAC;IAED,wBAAwB,CACtB,cAAsB,EACtB,aAAqB,EACrB,YAAsB;QAEtB,OAAO;;;wBAGa,cAAc;oBAClB,aAAa;;;;;;;;;mBASd,cAAc;kBACf,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;4BAyBH,cAAc;;;;;;EAMxC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QACpB,GAAG;gDACqC,GAAG,CAAC,WAAW,EAAE;;CAEhE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;+BAWkB,cAAc;6BAChB,aAAa;;;;EAIxC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;MACtB,GAAG,uCAAuC,GAAG;0BACzB,GAAG,CAAC,WAAW,EAAE,0BAA0B,GAAG;wBAChD,GAAG,CAAC,WAAW,EAAE,6BAA6B,GAAG;+BAC1C,GAAG,CAAC,WAAW,EAAE,mCAAmC,GAAG;CACrF,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;EAcX,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBxD,CAAC;IACA,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAyB,IAAI,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T042 & T051: Init orchestrator service
|
|
3
|
+
* Coordinates interactive prompts or flag-based config, generates scaffold files,
|
|
4
|
+
* and detects existing file conflicts
|
|
5
|
+
*/
|
|
6
|
+
import { InitConfig } from '../models/config.js';
|
|
7
|
+
export interface GeneratedFiles {
|
|
8
|
+
pipelines: string[];
|
|
9
|
+
configs: string[];
|
|
10
|
+
directories: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface InitService {
|
|
13
|
+
run(config: InitConfig): Promise<GeneratedFiles>;
|
|
14
|
+
}
|
|
15
|
+
export declare const initService: InitService;
|
|
16
|
+
//# sourceMappingURL=init-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-service.d.ts","sourceRoot":"","sources":["../../src/services/init-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA6BjD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAClD;AAqXD,eAAO,MAAM,WAAW,EAAE,WAAmC,CAAC"}
|