@scoutflo/topology-contracts 0.8.1 → 0.9.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/README.md +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/product-identity.d.ts +30 -0
- package/dist/src/product-identity.js +128 -0
- package/dist/src/product-identity.js.map +1 -0
- package/dist/test/product-identity.test.d.ts +1 -0
- package/dist/test/product-identity.test.js +103 -0
- package/dist/test/product-identity.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ This package owns:
|
|
|
12
12
|
- topology correlation contract endpoint, relation-class, family, and contract-key vocabulary;
|
|
13
13
|
- Gateway/Mongo-aligned topology resource and relation vocabulary constants useful at contract boundaries.
|
|
14
14
|
- the bounded, schema-validated Gateway-to-Voyager `alertContext.topologyContext` DTO.
|
|
15
|
+
- versioned, bounded Jira/JSM, Confluence, and Sentry product-key normalization that preserves raw evidence and provider scope.
|
|
15
16
|
|
|
16
17
|
## Gateway alert topology context
|
|
17
18
|
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const TOPOLOGY_CONTRACTS_PACKAGE = "@scoutflo/topology-contracts";
|
|
2
2
|
export * as correlationCore from '@scoutflo/correlation-core';
|
|
3
3
|
export * from './providers';
|
|
4
|
+
export * from './product-identity';
|
|
4
5
|
export * from './families';
|
|
5
6
|
export * from './source-sync';
|
|
6
7
|
export * from './correlation';
|
package/dist/src/index.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.correlationCore = exports.TOPOLOGY_CONTRACTS_PACKAGE = void 0;
|
|
|
40
40
|
exports.TOPOLOGY_CONTRACTS_PACKAGE = '@scoutflo/topology-contracts';
|
|
41
41
|
exports.correlationCore = __importStar(require("@scoutflo/correlation-core"));
|
|
42
42
|
__exportStar(require("./providers"), exports);
|
|
43
|
+
__exportStar(require("./product-identity"), exports);
|
|
43
44
|
__exportStar(require("./families"), exports);
|
|
44
45
|
__exportStar(require("./source-sync"), exports);
|
|
45
46
|
__exportStar(require("./correlation"), exports);
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAa,QAAA,0BAA0B,GAAG,8BAA8B,CAAC;AAEzE,8EAA8D;AAE9D,8CAA4B;AAC5B,6CAA2B;AAC3B,gDAA8B;AAC9B,gDAA8B;AAC9B,6CAA2B;AAC3B,kDAAgC;AAChC,sDAAoC;AACpC,+CAA6B;AAC7B,4CAA0B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAa,QAAA,0BAA0B,GAAG,8BAA8B,CAAC;AAEzE,8EAA8D;AAE9D,8CAA4B;AAC5B,qDAAmC;AACnC,6CAA2B;AAC3B,gDAA8B;AAC9B,gDAA8B;AAC9B,6CAA2B;AAC3B,kDAAgC;AAChC,sDAAoC;AACpC,+CAA6B;AAC7B,4CAA0B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const PROVIDER_PRODUCT_KEY_VERSION: "provider-product-key.v1";
|
|
2
|
+
export declare const PROVIDER_PRODUCT_KEY_PROVIDERS: readonly ["jira", "jsm", "confluence", "sentry"];
|
|
3
|
+
export type ProviderProductKeyProvider = (typeof PROVIDER_PRODUCT_KEY_PROVIDERS)[number];
|
|
4
|
+
export interface ProviderProductKeyInput {
|
|
5
|
+
provider: string;
|
|
6
|
+
raw_value: string;
|
|
7
|
+
account_key: string;
|
|
8
|
+
integration_id: string;
|
|
9
|
+
project_id?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface NormalizedProviderProductKey {
|
|
12
|
+
version: typeof PROVIDER_PRODUCT_KEY_VERSION;
|
|
13
|
+
provider: ProviderProductKeyProvider;
|
|
14
|
+
raw_value: string;
|
|
15
|
+
canonical_key: string;
|
|
16
|
+
account_key: string;
|
|
17
|
+
integration_id: string;
|
|
18
|
+
project_id?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const SENTRY_RELEASE_CLAIM_VERSION: "sentry-release-claim.v1";
|
|
21
|
+
export interface SentryReleaseClaim {
|
|
22
|
+
version: typeof SENTRY_RELEASE_CLAIM_VERSION;
|
|
23
|
+
raw_value: string;
|
|
24
|
+
release_name?: string;
|
|
25
|
+
semantic_version?: string;
|
|
26
|
+
revision?: string;
|
|
27
|
+
immutable_revision: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function normalizeProviderProductKey(input: ProviderProductKeyInput): NormalizedProviderProductKey | undefined;
|
|
30
|
+
export declare function parseSentryReleaseClaim(rawValue: string): SentryReleaseClaim | undefined;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SENTRY_RELEASE_CLAIM_VERSION = exports.PROVIDER_PRODUCT_KEY_PROVIDERS = exports.PROVIDER_PRODUCT_KEY_VERSION = void 0;
|
|
4
|
+
exports.normalizeProviderProductKey = normalizeProviderProductKey;
|
|
5
|
+
exports.parseSentryReleaseClaim = parseSentryReleaseClaim;
|
|
6
|
+
exports.PROVIDER_PRODUCT_KEY_VERSION = 'provider-product-key.v1';
|
|
7
|
+
exports.PROVIDER_PRODUCT_KEY_PROVIDERS = ['jira', 'jsm', 'confluence', 'sentry'];
|
|
8
|
+
exports.SENTRY_RELEASE_CLAIM_VERSION = 'sentry-release-claim.v1';
|
|
9
|
+
const MAX_RAW_LENGTH = 512;
|
|
10
|
+
const MAX_KEY_LENGTH = 128;
|
|
11
|
+
const BOUNDED_SCOPE_LENGTH = 180;
|
|
12
|
+
const PROVIDERS = new Set(exports.PROVIDER_PRODUCT_KEY_PROVIDERS);
|
|
13
|
+
const FULL_COMMIT_SHA = /^[0-9a-f]{40}$/i;
|
|
14
|
+
const SEMANTIC_VERSION = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
15
|
+
function boundedScope(value) {
|
|
16
|
+
const rendered = value.trim();
|
|
17
|
+
return rendered && rendered.length <= BOUNDED_SCOPE_LENGTH ? rendered : undefined;
|
|
18
|
+
}
|
|
19
|
+
function safeDecode(value) {
|
|
20
|
+
try {
|
|
21
|
+
return decodeURIComponent(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function valueFromUrl(provider, raw) {
|
|
28
|
+
const trimmed = raw.trim();
|
|
29
|
+
const jiraIssue = trimmed.match(/\/browse\/\s*([A-Za-z][A-Za-z0-9_-]*)-\d+(?:[/?#]|$)/i)?.[1];
|
|
30
|
+
if ((provider === 'jira' || provider === 'jsm') && jiraIssue) {
|
|
31
|
+
return jiraIssue;
|
|
32
|
+
}
|
|
33
|
+
const confluenceSpace = trimmed.match(/\/spaces\/([^/?#]+)/i)?.[1];
|
|
34
|
+
if (provider === 'confluence' && confluenceSpace) {
|
|
35
|
+
return safeDecode(confluenceSpace);
|
|
36
|
+
}
|
|
37
|
+
if (provider === 'sentry') {
|
|
38
|
+
const queryProject = trimmed.match(/[?&]project=([^&#]+)/i)?.[1];
|
|
39
|
+
if (queryProject) {
|
|
40
|
+
return safeDecode(queryProject.replace(/\+/g, ' '));
|
|
41
|
+
}
|
|
42
|
+
const pathProject = trimmed.match(/\/projects\/[^/?#]+\/([^/?#]+)/i)?.[1];
|
|
43
|
+
if (pathProject) {
|
|
44
|
+
return safeDecode(pathProject);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
function providerValue(provider, raw) {
|
|
50
|
+
const urlValue = valueFromUrl(provider, raw);
|
|
51
|
+
if (urlValue) {
|
|
52
|
+
return urlValue;
|
|
53
|
+
}
|
|
54
|
+
if (provider === 'jira' || provider === 'jsm') {
|
|
55
|
+
return raw.trim().replace(/-\d+$/, '');
|
|
56
|
+
}
|
|
57
|
+
return raw.trim();
|
|
58
|
+
}
|
|
59
|
+
function canonicalize(value) {
|
|
60
|
+
const normalized = value
|
|
61
|
+
.normalize('NFKC')
|
|
62
|
+
.toLowerCase()
|
|
63
|
+
.replace(/[\s_]+/g, '-')
|
|
64
|
+
.replace(/[^\p{Letter}\p{Number}.-]+/gu, '-')
|
|
65
|
+
.replace(/-{2,}/g, '-')
|
|
66
|
+
.replace(/^[.-]+|[.-]+$/g, '')
|
|
67
|
+
.slice(0, MAX_KEY_LENGTH);
|
|
68
|
+
return normalized || undefined;
|
|
69
|
+
}
|
|
70
|
+
function normalizeProviderProductKey(input) {
|
|
71
|
+
const provider = input.provider.trim().toLowerCase();
|
|
72
|
+
if (!PROVIDERS.has(provider) || typeof input.raw_value !== 'string' || input.raw_value.length > MAX_RAW_LENGTH) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const accountKey = boundedScope(input.account_key);
|
|
76
|
+
const integrationId = boundedScope(input.integration_id);
|
|
77
|
+
const projectId = input.project_id === undefined ? undefined : boundedScope(input.project_id);
|
|
78
|
+
const canonicalKey = canonicalize(providerValue(provider, input.raw_value));
|
|
79
|
+
if (!accountKey || !integrationId || !canonicalKey || (input.project_id !== undefined && !projectId)) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
version: exports.PROVIDER_PRODUCT_KEY_VERSION,
|
|
84
|
+
provider: provider,
|
|
85
|
+
raw_value: input.raw_value,
|
|
86
|
+
canonical_key: canonicalKey,
|
|
87
|
+
account_key: accountKey,
|
|
88
|
+
integration_id: integrationId,
|
|
89
|
+
...(projectId ? { project_id: projectId } : {}),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseSentryReleaseClaim(rawValue) {
|
|
93
|
+
if (typeof rawValue !== 'string' || rawValue.length > 256) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const rendered = rawValue.trim();
|
|
97
|
+
if (!rendered) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (FULL_COMMIT_SHA.test(rendered)) {
|
|
101
|
+
return {
|
|
102
|
+
version: exports.SENTRY_RELEASE_CLAIM_VERSION,
|
|
103
|
+
raw_value: rawValue,
|
|
104
|
+
revision: rendered.toLowerCase(),
|
|
105
|
+
immutable_revision: true,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const atIndex = rendered.lastIndexOf('@');
|
|
109
|
+
const releaseName = atIndex > 0 ? rendered.slice(0, atIndex).trim() : undefined;
|
|
110
|
+
const versionCandidate = atIndex > 0 ? rendered.slice(atIndex + 1).trim() : rendered;
|
|
111
|
+
const semanticMatch = SEMANTIC_VERSION.exec(versionCandidate);
|
|
112
|
+
if (semanticMatch) {
|
|
113
|
+
return {
|
|
114
|
+
version: exports.SENTRY_RELEASE_CLAIM_VERSION,
|
|
115
|
+
raw_value: rawValue,
|
|
116
|
+
...(releaseName ? { release_name: releaseName } : {}),
|
|
117
|
+
semantic_version: versionCandidate.replace(/^v/i, ''),
|
|
118
|
+
immutable_revision: false,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
version: exports.SENTRY_RELEASE_CLAIM_VERSION,
|
|
123
|
+
raw_value: rawValue,
|
|
124
|
+
release_name: rendered,
|
|
125
|
+
immutable_revision: false,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=product-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-identity.js","sourceRoot":"","sources":["../../src/product-identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const product_identity_1 = require("../src/product-identity");
|
|
9
|
+
const scope = {
|
|
10
|
+
account_key: 'acme.example',
|
|
11
|
+
integration_id: 'integration-42',
|
|
12
|
+
};
|
|
13
|
+
(0, node_test_1.default)('normalizes Jira and JSM project keys while preserving raw evidence and scope', () => {
|
|
14
|
+
for (const provider of ['jira', 'jsm']) {
|
|
15
|
+
strict_1.default.deepEqual((0, product_identity_1.normalizeProviderProductKey)({
|
|
16
|
+
provider,
|
|
17
|
+
raw_value: ' https://acme.atlassian.net/browse/ PAY-123?focusedCommentId=9 ',
|
|
18
|
+
...scope,
|
|
19
|
+
}), {
|
|
20
|
+
version: 'provider-product-key.v1',
|
|
21
|
+
provider,
|
|
22
|
+
raw_value: ' https://acme.atlassian.net/browse/ PAY-123?focusedCommentId=9 ',
|
|
23
|
+
canonical_key: 'pay',
|
|
24
|
+
account_key: 'acme.example',
|
|
25
|
+
integration_id: 'integration-42',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.default)('normalizes Confluence URL-derived Unicode space keys deterministically', () => {
|
|
30
|
+
strict_1.default.equal((0, product_identity_1.normalizeProviderProductKey)({
|
|
31
|
+
provider: 'confluence',
|
|
32
|
+
raw_value: 'https://acme.atlassian.net/wiki/spaces/Platform%20Caf%C3%A9/pages/123',
|
|
33
|
+
...scope,
|
|
34
|
+
})?.canonical_key, 'platform-café');
|
|
35
|
+
});
|
|
36
|
+
(0, node_test_1.default)('normalizes Sentry project slugs without collapsing project scope', () => {
|
|
37
|
+
strict_1.default.deepEqual((0, product_identity_1.normalizeProviderProductKey)({
|
|
38
|
+
provider: 'sentry',
|
|
39
|
+
raw_value: ' HTTPS://sentry.io/organizations/acme/issues/?project=Payments_API ',
|
|
40
|
+
project_id: '4500123',
|
|
41
|
+
...scope,
|
|
42
|
+
}), {
|
|
43
|
+
version: 'provider-product-key.v1',
|
|
44
|
+
provider: 'sentry',
|
|
45
|
+
raw_value: ' HTTPS://sentry.io/organizations/acme/issues/?project=Payments_API ',
|
|
46
|
+
canonical_key: 'payments-api',
|
|
47
|
+
account_key: 'acme.example',
|
|
48
|
+
integration_id: 'integration-42',
|
|
49
|
+
project_id: '4500123',
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
(0, node_test_1.default)('rejects unsupported providers and unbounded or empty keys', () => {
|
|
53
|
+
strict_1.default.equal((0, product_identity_1.normalizeProviderProductKey)({ provider: 'github', raw_value: 'repo', ...scope }), undefined);
|
|
54
|
+
strict_1.default.equal((0, product_identity_1.normalizeProviderProductKey)({ provider: 'sentry', raw_value: ' '.repeat(3), ...scope }), undefined);
|
|
55
|
+
strict_1.default.equal((0, product_identity_1.normalizeProviderProductKey)({ provider: 'sentry', raw_value: 'x'.repeat(513), ...scope }), undefined);
|
|
56
|
+
});
|
|
57
|
+
(0, node_test_1.default)('keeps identical canonical keys distinct through required provider scope', () => {
|
|
58
|
+
const first = (0, product_identity_1.normalizeProviderProductKey)({
|
|
59
|
+
provider: 'sentry',
|
|
60
|
+
raw_value: 'Payments API',
|
|
61
|
+
account_key: 'account-a',
|
|
62
|
+
integration_id: 'integration-a',
|
|
63
|
+
project_id: '1',
|
|
64
|
+
});
|
|
65
|
+
const second = (0, product_identity_1.normalizeProviderProductKey)({
|
|
66
|
+
provider: 'sentry',
|
|
67
|
+
raw_value: 'payments-api',
|
|
68
|
+
account_key: 'account-b',
|
|
69
|
+
integration_id: 'integration-b',
|
|
70
|
+
project_id: '2',
|
|
71
|
+
});
|
|
72
|
+
strict_1.default.equal(first?.canonical_key, second?.canonical_key);
|
|
73
|
+
strict_1.default.notDeepEqual(first, second);
|
|
74
|
+
});
|
|
75
|
+
(0, node_test_1.default)('parses bounded semantic versions and named releases into structured claims', () => {
|
|
76
|
+
strict_1.default.deepEqual((0, product_identity_1.parseSentryReleaseClaim)('payments-api@1.24.3+build.7'), {
|
|
77
|
+
version: 'sentry-release-claim.v1',
|
|
78
|
+
raw_value: 'payments-api@1.24.3+build.7',
|
|
79
|
+
release_name: 'payments-api',
|
|
80
|
+
semantic_version: '1.24.3+build.7',
|
|
81
|
+
immutable_revision: false,
|
|
82
|
+
});
|
|
83
|
+
strict_1.default.deepEqual((0, product_identity_1.parseSentryReleaseClaim)('v2.0.1-rc.2'), {
|
|
84
|
+
version: 'sentry-release-claim.v1',
|
|
85
|
+
raw_value: 'v2.0.1-rc.2',
|
|
86
|
+
semantic_version: '2.0.1-rc.2',
|
|
87
|
+
immutable_revision: false,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
(0, node_test_1.default)('accepts only full commit SHAs as immutable Sentry release evidence', () => {
|
|
91
|
+
const sha = '0123456789abcdef0123456789abcdef01234567';
|
|
92
|
+
strict_1.default.deepEqual((0, product_identity_1.parseSentryReleaseClaim)(sha), {
|
|
93
|
+
version: 'sentry-release-claim.v1',
|
|
94
|
+
raw_value: sha,
|
|
95
|
+
revision: sha,
|
|
96
|
+
immutable_revision: true,
|
|
97
|
+
});
|
|
98
|
+
strict_1.default.equal((0, product_identity_1.parseSentryReleaseClaim)('main')?.immutable_revision, false);
|
|
99
|
+
strict_1.default.equal((0, product_identity_1.parseSentryReleaseClaim)('v1.2')?.immutable_revision, false);
|
|
100
|
+
strict_1.default.equal((0, product_identity_1.parseSentryReleaseClaim)('0123456789ab')?.immutable_revision, false);
|
|
101
|
+
strict_1.default.equal((0, product_identity_1.parseSentryReleaseClaim)('x'.repeat(257)), undefined);
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=product-identity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-identity.test.js","sourceRoot":"","sources":["../../test/product-identity.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED