hackmyagent-core 0.1.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/dist/checker/check-skill.d.ts +48 -0
- package/dist/checker/check-skill.d.ts.map +1 -0
- package/dist/checker/check-skill.js +105 -0
- package/dist/checker/check-skill.js.map +1 -0
- package/dist/checker/check-skill.test.d.ts +2 -0
- package/dist/checker/check-skill.test.d.ts.map +1 -0
- package/dist/checker/check-skill.test.js +83 -0
- package/dist/checker/check-skill.test.js.map +1 -0
- package/dist/checker/index.d.ts +12 -0
- package/dist/checker/index.d.ts.map +1 -0
- package/dist/checker/index.js +16 -0
- package/dist/checker/index.js.map +1 -0
- package/dist/checker/permission-analyzer.d.ts +12 -0
- package/dist/checker/permission-analyzer.d.ts.map +1 -0
- package/dist/checker/permission-analyzer.js +84 -0
- package/dist/checker/permission-analyzer.js.map +1 -0
- package/dist/checker/permission-analyzer.test.d.ts +2 -0
- package/dist/checker/permission-analyzer.test.d.ts.map +1 -0
- package/dist/checker/permission-analyzer.test.js +87 -0
- package/dist/checker/permission-analyzer.test.js.map +1 -0
- package/dist/checker/publisher-verifier.d.ts +34 -0
- package/dist/checker/publisher-verifier.d.ts.map +1 -0
- package/dist/checker/publisher-verifier.js +121 -0
- package/dist/checker/publisher-verifier.js.map +1 -0
- package/dist/checker/publisher-verifier.test.d.ts +2 -0
- package/dist/checker/publisher-verifier.test.d.ts.map +1 -0
- package/dist/checker/publisher-verifier.test.js +171 -0
- package/dist/checker/publisher-verifier.test.js.map +1 -0
- package/dist/checker/skill-identifier.d.ts +14 -0
- package/dist/checker/skill-identifier.d.ts.map +1 -0
- package/dist/checker/skill-identifier.js +55 -0
- package/dist/checker/skill-identifier.js.map +1 -0
- package/dist/checker/skill-identifier.test.d.ts +2 -0
- package/dist/checker/skill-identifier.test.d.ts.map +1 -0
- package/dist/checker/skill-identifier.test.js +64 -0
- package/dist/checker/skill-identifier.test.js.map +1 -0
- package/dist/hardening/index.d.ts +7 -0
- package/dist/hardening/index.d.ts.map +1 -0
- package/dist/hardening/index.js +9 -0
- package/dist/hardening/index.js.map +1 -0
- package/dist/hardening/scanner.d.ts +85 -0
- package/dist/hardening/scanner.d.ts.map +1 -0
- package/dist/hardening/scanner.js +3410 -0
- package/dist/hardening/scanner.js.map +1 -0
- package/dist/hardening/scanner.test.d.ts +2 -0
- package/dist/hardening/scanner.test.d.ts.map +1 -0
- package/dist/hardening/scanner.test.js +1103 -0
- package/dist/hardening/scanner.test.js.map +1 -0
- package/dist/hardening/security-check.d.ts +56 -0
- package/dist/hardening/security-check.d.ts.map +1 -0
- package/dist/hardening/security-check.js +6 -0
- package/dist/hardening/security-check.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/external-scanner.d.ts +13 -0
- package/dist/scanner/external-scanner.d.ts.map +1 -0
- package/dist/scanner/external-scanner.js +299 -0
- package/dist/scanner/external-scanner.js.map +1 -0
- package/dist/scanner/external-scanner.test.d.ts +2 -0
- package/dist/scanner/external-scanner.test.d.ts.map +1 -0
- package/dist/scanner/external-scanner.test.js +302 -0
- package/dist/scanner/external-scanner.test.js.map +1 -0
- package/dist/scanner/index.d.ts +6 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +9 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/types.d.ts +32 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +6 -0
- package/dist/scanner/types.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill checker
|
|
3
|
+
* Main entry point for checking a skill's safety
|
|
4
|
+
*/
|
|
5
|
+
import { type VerifyOptions } from './publisher-verifier';
|
|
6
|
+
export type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
|
|
7
|
+
export interface PublisherInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
verified: boolean;
|
|
10
|
+
verificationMethod?: 'dns' | 'github' | 'none';
|
|
11
|
+
domain?: string;
|
|
12
|
+
verifiedAt?: Date;
|
|
13
|
+
failureReason?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PermissionInfo {
|
|
16
|
+
requested: string[];
|
|
17
|
+
safe: string[];
|
|
18
|
+
dangerous: string[];
|
|
19
|
+
reviewNeeded: string[];
|
|
20
|
+
riskScore: number;
|
|
21
|
+
}
|
|
22
|
+
export interface RevocationInfo {
|
|
23
|
+
revoked: boolean;
|
|
24
|
+
reason?: string;
|
|
25
|
+
revokedAt?: Date;
|
|
26
|
+
checkedAt: Date;
|
|
27
|
+
}
|
|
28
|
+
export interface CheckResult {
|
|
29
|
+
skillId: string;
|
|
30
|
+
publisher: PublisherInfo;
|
|
31
|
+
permissions: PermissionInfo;
|
|
32
|
+
revocation: RevocationInfo;
|
|
33
|
+
risk: RiskLevel;
|
|
34
|
+
}
|
|
35
|
+
export interface CheckOptions {
|
|
36
|
+
manifest?: {
|
|
37
|
+
permissions?: string[];
|
|
38
|
+
};
|
|
39
|
+
/** Skip real DNS verification (for testing) */
|
|
40
|
+
mockVerified?: boolean;
|
|
41
|
+
mockRevoked?: boolean;
|
|
42
|
+
/** Skip DNS lookup entirely (offline mode) */
|
|
43
|
+
skipDnsVerification?: boolean;
|
|
44
|
+
/** Options passed to verifyPublisher */
|
|
45
|
+
verifyOptions?: VerifyOptions;
|
|
46
|
+
}
|
|
47
|
+
export declare function checkSkill(skillId: string, options?: CheckOptions): Promise<CheckResult>;
|
|
48
|
+
//# sourceMappingURL=check-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-skill.d.ts","sourceRoot":"","sources":["../../src/checker/check-skill.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE3E,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE;QACT,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IACF,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,wCAAwC;IACxC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC,CAgCtB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Skill checker
|
|
4
|
+
* Main entry point for checking a skill's safety
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.checkSkill = checkSkill;
|
|
8
|
+
const skill_identifier_1 = require("./skill-identifier");
|
|
9
|
+
const permission_analyzer_1 = require("./permission-analyzer");
|
|
10
|
+
const publisher_verifier_1 = require("./publisher-verifier");
|
|
11
|
+
async function checkSkill(skillId, options) {
|
|
12
|
+
// Parse skill identifier
|
|
13
|
+
const parsed = (0, skill_identifier_1.parseSkillIdentifier)(skillId);
|
|
14
|
+
// Get publisher info
|
|
15
|
+
const publisher = await getPublisherInfo(parsed.publisher, options);
|
|
16
|
+
// Get permissions from manifest
|
|
17
|
+
const requestedPermissions = options?.manifest?.permissions ?? [];
|
|
18
|
+
const permissionAnalysis = (0, permission_analyzer_1.analyzePermissions)(requestedPermissions);
|
|
19
|
+
const permissions = {
|
|
20
|
+
requested: requestedPermissions,
|
|
21
|
+
safe: permissionAnalysis.safe,
|
|
22
|
+
dangerous: permissionAnalysis.dangerous,
|
|
23
|
+
reviewNeeded: permissionAnalysis.reviewNeeded,
|
|
24
|
+
riskScore: permissionAnalysis.riskScore,
|
|
25
|
+
};
|
|
26
|
+
// Check revocation status
|
|
27
|
+
const revocation = await checkRevocation(skillId, options);
|
|
28
|
+
// Calculate overall risk
|
|
29
|
+
const risk = calculateRisk(publisher, permissions, revocation);
|
|
30
|
+
return {
|
|
31
|
+
skillId,
|
|
32
|
+
publisher,
|
|
33
|
+
permissions,
|
|
34
|
+
revocation,
|
|
35
|
+
risk,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function getPublisherInfo(publisherName, options) {
|
|
39
|
+
const name = publisherName ?? 'unknown';
|
|
40
|
+
// Handle mock verification for testing (backwards compatible)
|
|
41
|
+
if (options?.mockVerified !== undefined) {
|
|
42
|
+
return {
|
|
43
|
+
name,
|
|
44
|
+
verified: options.mockVerified,
|
|
45
|
+
verificationMethod: options.mockVerified ? 'dns' : 'none',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Skip DNS verification if requested (offline mode)
|
|
49
|
+
if (options?.skipDnsVerification) {
|
|
50
|
+
return {
|
|
51
|
+
name,
|
|
52
|
+
verified: false,
|
|
53
|
+
verificationMethod: 'none',
|
|
54
|
+
failureReason: 'DNS verification skipped (offline mode)',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Perform real DNS verification
|
|
58
|
+
const verification = await (0, publisher_verifier_1.verifyPublisher)(name, options?.verifyOptions);
|
|
59
|
+
return {
|
|
60
|
+
name,
|
|
61
|
+
verified: verification.verified,
|
|
62
|
+
verificationMethod: verification.method,
|
|
63
|
+
domain: verification.domain,
|
|
64
|
+
verifiedAt: verification.verifiedAt,
|
|
65
|
+
failureReason: verification.failureReason,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function checkRevocation(skillId, options) {
|
|
69
|
+
const checkedAt = new Date();
|
|
70
|
+
// Handle mock revocation for testing
|
|
71
|
+
if (options?.mockRevoked) {
|
|
72
|
+
return {
|
|
73
|
+
revoked: true,
|
|
74
|
+
reason: 'Skill has been revoked for security reasons',
|
|
75
|
+
revokedAt: new Date(),
|
|
76
|
+
checkedAt,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Known revoked skills (in production, this would query a revocation list)
|
|
80
|
+
const revokedSkills = new Set(['@malicious/bad-skill']);
|
|
81
|
+
const revoked = revokedSkills.has(skillId);
|
|
82
|
+
return {
|
|
83
|
+
revoked,
|
|
84
|
+
reason: revoked ? 'Skill has been revoked for security reasons' : undefined,
|
|
85
|
+
revokedAt: revoked ? new Date() : undefined,
|
|
86
|
+
checkedAt,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function calculateRisk(publisher, permissions, revocation) {
|
|
90
|
+
// Critical: skill is revoked
|
|
91
|
+
if (revocation.revoked) {
|
|
92
|
+
return 'critical';
|
|
93
|
+
}
|
|
94
|
+
// High: dangerous permissions
|
|
95
|
+
if (permissions.dangerous.length > 0) {
|
|
96
|
+
return 'high';
|
|
97
|
+
}
|
|
98
|
+
// Medium: unverified publisher or permissions needing review
|
|
99
|
+
if (!publisher.verified || permissions.reviewNeeded.length > 0) {
|
|
100
|
+
return 'medium';
|
|
101
|
+
}
|
|
102
|
+
// Low: verified publisher with safe permissions
|
|
103
|
+
return 'low';
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=check-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-skill.js","sourceRoot":"","sources":["../../src/checker/check-skill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-skill.test.d.ts","sourceRoot":"","sources":["../../src/checker/check-skill.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const check_skill_1 = require("./check-skill");
|
|
5
|
+
(0, vitest_1.describe)('checkSkill', () => {
|
|
6
|
+
(0, vitest_1.it)('returns a check result with publisher, permissions, and revocation status', async () => {
|
|
7
|
+
const result = await (0, check_skill_1.checkSkill)('@opena2a/security');
|
|
8
|
+
(0, vitest_1.expect)(result).toMatchObject({
|
|
9
|
+
skillId: '@opena2a/security',
|
|
10
|
+
publisher: vitest_1.expect.any(Object),
|
|
11
|
+
permissions: vitest_1.expect.any(Object),
|
|
12
|
+
revocation: vitest_1.expect.any(Object),
|
|
13
|
+
risk: vitest_1.expect.any(String),
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.it)('identifies unverified publisher as higher risk', async () => {
|
|
17
|
+
// Unknown publisher with no verification
|
|
18
|
+
const result = await (0, check_skill_1.checkSkill)('@unknown-dev/sketchy-tool');
|
|
19
|
+
(0, vitest_1.expect)(result.publisher.verified).toBe(false);
|
|
20
|
+
(0, vitest_1.expect)(['medium', 'high', 'critical']).toContain(result.risk);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)('flags dangerous permissions', async () => {
|
|
23
|
+
// Skill requesting shell access should be flagged
|
|
24
|
+
const result = await (0, check_skill_1.checkSkill)('@test/shell-skill', {
|
|
25
|
+
manifest: {
|
|
26
|
+
permissions: ['shell:execute', 'filesystem:*'],
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.expect)(result.permissions.dangerous).toContain('shell:execute');
|
|
30
|
+
(0, vitest_1.expect)(result.permissions.dangerous).toContain('filesystem:*');
|
|
31
|
+
(0, vitest_1.expect)(result.risk).toBe('high');
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('checks revocation status', async () => {
|
|
34
|
+
const result = await (0, check_skill_1.checkSkill)('@opena2a/security');
|
|
35
|
+
(0, vitest_1.expect)(result.revocation).toMatchObject({
|
|
36
|
+
revoked: vitest_1.expect.any(Boolean),
|
|
37
|
+
checkedAt: vitest_1.expect.any(Date),
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('returns critical risk for revoked skills', async () => {
|
|
41
|
+
const result = await (0, check_skill_1.checkSkill)('@malicious/bad-skill', {
|
|
42
|
+
mockRevoked: true,
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.expect)(result.revocation.revoked).toBe(true);
|
|
45
|
+
(0, vitest_1.expect)(result.risk).toBe('critical');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.describe)('RiskLevel calculation', () => {
|
|
49
|
+
(0, vitest_1.it)('is low when publisher verified and permissions minimal', async () => {
|
|
50
|
+
const result = await (0, check_skill_1.checkSkill)('@verified/safe-skill', {
|
|
51
|
+
mockVerified: true,
|
|
52
|
+
manifest: {
|
|
53
|
+
permissions: ['messages:read'],
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
(0, vitest_1.expect)(result.risk).toBe('low');
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)('is medium when publisher unverified but permissions safe', async () => {
|
|
59
|
+
const result = await (0, check_skill_1.checkSkill)('@unverified/safe-skill', {
|
|
60
|
+
mockVerified: false,
|
|
61
|
+
manifest: {
|
|
62
|
+
permissions: ['messages:read'],
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
(0, vitest_1.expect)(result.risk).toBe('medium');
|
|
66
|
+
});
|
|
67
|
+
(0, vitest_1.it)('is high when dangerous permissions requested', async () => {
|
|
68
|
+
const result = await (0, check_skill_1.checkSkill)('@verified/risky-skill', {
|
|
69
|
+
mockVerified: true,
|
|
70
|
+
manifest: {
|
|
71
|
+
permissions: ['shell:execute'],
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.expect)(result.risk).toBe('high');
|
|
75
|
+
});
|
|
76
|
+
(0, vitest_1.it)('is critical when skill is revoked', async () => {
|
|
77
|
+
const result = await (0, check_skill_1.checkSkill)('@any/revoked-skill', {
|
|
78
|
+
mockRevoked: true,
|
|
79
|
+
});
|
|
80
|
+
(0, vitest_1.expect)(result.risk).toBe('critical');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=check-skill.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-skill.test.js","sourceRoot":"","sources":["../../src/checker/check-skill.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill checker module
|
|
3
|
+
*/
|
|
4
|
+
export { parseSkillIdentifier } from './skill-identifier';
|
|
5
|
+
export type { SkillIdentifier } from './skill-identifier';
|
|
6
|
+
export { analyzePermissions } from './permission-analyzer';
|
|
7
|
+
export type { PermissionAnalysis } from './permission-analyzer';
|
|
8
|
+
export { verifyPublisher, lookupDnsTxt } from './publisher-verifier';
|
|
9
|
+
export type { PublisherVerification, VerificationMethod, VerifyOptions, } from './publisher-verifier';
|
|
10
|
+
export { checkSkill } from './check-skill';
|
|
11
|
+
export type { CheckResult, CheckOptions, PublisherInfo, PermissionInfo, RevocationInfo, RiskLevel, } from './check-skill';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checker/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,YAAY,EACV,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,EACd,SAAS,GACV,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Skill checker module
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkSkill = exports.lookupDnsTxt = exports.verifyPublisher = exports.analyzePermissions = exports.parseSkillIdentifier = void 0;
|
|
7
|
+
var skill_identifier_1 = require("./skill-identifier");
|
|
8
|
+
Object.defineProperty(exports, "parseSkillIdentifier", { enumerable: true, get: function () { return skill_identifier_1.parseSkillIdentifier; } });
|
|
9
|
+
var permission_analyzer_1 = require("./permission-analyzer");
|
|
10
|
+
Object.defineProperty(exports, "analyzePermissions", { enumerable: true, get: function () { return permission_analyzer_1.analyzePermissions; } });
|
|
11
|
+
var publisher_verifier_1 = require("./publisher-verifier");
|
|
12
|
+
Object.defineProperty(exports, "verifyPublisher", { enumerable: true, get: function () { return publisher_verifier_1.verifyPublisher; } });
|
|
13
|
+
Object.defineProperty(exports, "lookupDnsTxt", { enumerable: true, get: function () { return publisher_verifier_1.lookupDnsTxt; } });
|
|
14
|
+
var check_skill_1 = require("./check-skill");
|
|
15
|
+
Object.defineProperty(exports, "checkSkill", { enumerable: true, get: function () { return check_skill_1.checkSkill; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checker/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,uDAA0D;AAAjD,wHAAA,oBAAoB,OAAA;AAG7B,6DAA2D;AAAlD,yHAAA,kBAAkB,OAAA;AAG3B,2DAAqE;AAA5D,qHAAA,eAAe,OAAA;AAAE,kHAAA,YAAY,OAAA;AAOtC,6CAA2C;AAAlC,yGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission analyzer
|
|
3
|
+
* Analyzes skill permissions and categorizes them by risk level
|
|
4
|
+
*/
|
|
5
|
+
export interface PermissionAnalysis {
|
|
6
|
+
safe: string[];
|
|
7
|
+
dangerous: string[];
|
|
8
|
+
reviewNeeded: string[];
|
|
9
|
+
riskScore: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function analyzePermissions(permissions: string[]): PermissionAnalysis;
|
|
12
|
+
//# sourceMappingURL=permission-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-analyzer.d.ts","sourceRoot":"","sources":["../../src/checker/permission-analyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AA0BD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAoC5E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Permission analyzer
|
|
4
|
+
* Analyzes skill permissions and categorizes them by risk level
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.analyzePermissions = analyzePermissions;
|
|
8
|
+
// Permissions that are always safe (read-only, limited scope)
|
|
9
|
+
const SAFE_PERMISSIONS = new Set([
|
|
10
|
+
'messages:read',
|
|
11
|
+
'config:read',
|
|
12
|
+
'storage:local',
|
|
13
|
+
]);
|
|
14
|
+
// Patterns that indicate dangerous permissions
|
|
15
|
+
const DANGEROUS_PATTERNS = [
|
|
16
|
+
/^shell:/, // Any shell access
|
|
17
|
+
/^filesystem:\*$/, // Wildcard filesystem
|
|
18
|
+
/^filesystem:\/$/, // Root filesystem
|
|
19
|
+
/^filesystem:~$/, // Home directory (broad)
|
|
20
|
+
/^network:\*$/, // Wildcard network
|
|
21
|
+
/^mcp:\*$/, // Wildcard MCP
|
|
22
|
+
];
|
|
23
|
+
// Patterns that need review (scoped but still sensitive)
|
|
24
|
+
const REVIEW_PATTERNS = [
|
|
25
|
+
/^filesystem:~\/.+/, // Scoped home directory paths
|
|
26
|
+
/^network:[^*]+$/, // Specific network hosts
|
|
27
|
+
/^mcp:[^*]+$/, // Specific MCP servers
|
|
28
|
+
];
|
|
29
|
+
function analyzePermissions(permissions) {
|
|
30
|
+
const safe = [];
|
|
31
|
+
const dangerous = [];
|
|
32
|
+
const reviewNeeded = [];
|
|
33
|
+
for (const permission of permissions) {
|
|
34
|
+
if (SAFE_PERMISSIONS.has(permission)) {
|
|
35
|
+
safe.push(permission);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const isDangerous = DANGEROUS_PATTERNS.some((pattern) => pattern.test(permission));
|
|
39
|
+
if (isDangerous) {
|
|
40
|
+
dangerous.push(permission);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const needsReview = REVIEW_PATTERNS.some((pattern) => pattern.test(permission));
|
|
44
|
+
if (needsReview) {
|
|
45
|
+
reviewNeeded.push(permission);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// Default: if not recognized, mark as needing review
|
|
49
|
+
reviewNeeded.push(permission);
|
|
50
|
+
}
|
|
51
|
+
// Calculate risk score (0-100)
|
|
52
|
+
const riskScore = calculateRiskScore(safe, dangerous, reviewNeeded);
|
|
53
|
+
return {
|
|
54
|
+
safe,
|
|
55
|
+
dangerous,
|
|
56
|
+
reviewNeeded,
|
|
57
|
+
riskScore,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function calculateRiskScore(safe, dangerous, reviewNeeded) {
|
|
61
|
+
if (safe.length === 0 && dangerous.length === 0 && reviewNeeded.length === 0) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
// Weights for each category
|
|
65
|
+
const SAFE_WEIGHT = 5;
|
|
66
|
+
const REVIEW_WEIGHT = 25;
|
|
67
|
+
const DANGEROUS_WEIGHT = 50;
|
|
68
|
+
const totalPermissions = safe.length + dangerous.length + reviewNeeded.length;
|
|
69
|
+
const weightedSum = safe.length * SAFE_WEIGHT +
|
|
70
|
+
reviewNeeded.length * REVIEW_WEIGHT +
|
|
71
|
+
dangerous.length * DANGEROUS_WEIGHT;
|
|
72
|
+
// Normalize to 0-100, with a minimum based on dangerous permissions
|
|
73
|
+
const baseScore = Math.min(100, (weightedSum / totalPermissions));
|
|
74
|
+
// If any dangerous permissions, ensure minimum score of 71
|
|
75
|
+
if (dangerous.length > 0) {
|
|
76
|
+
return Math.max(71, baseScore);
|
|
77
|
+
}
|
|
78
|
+
// If only review-needed, ensure minimum score of 31
|
|
79
|
+
if (reviewNeeded.length > 0 && safe.length === 0) {
|
|
80
|
+
return Math.max(31, baseScore);
|
|
81
|
+
}
|
|
82
|
+
return baseScore;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=permission-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-analyzer.js","sourceRoot":"","sources":["../../src/checker/permission-analyzer.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAiCH,gDAoCC;AA5DD,8DAA8D;AAC9D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,eAAe;IACf,aAAa;IACb,eAAe;CAChB,CAAC,CAAC;AAEH,+CAA+C;AAC/C,MAAM,kBAAkB,GAAG;IACzB,SAAS,EAAY,mBAAmB;IACxC,iBAAiB,EAAI,sBAAsB;IAC3C,iBAAiB,EAAI,kBAAkB;IACvC,gBAAgB,EAAK,yBAAyB;IAC9C,cAAc,EAAO,mBAAmB;IACxC,UAAU,EAAW,eAAe;CACrC,CAAC;AAEF,yDAAyD;AACzD,MAAM,eAAe,GAAG;IACtB,mBAAmB,EAAE,8BAA8B;IACnD,iBAAiB,EAAI,yBAAyB;IAC9C,aAAa,EAAQ,uBAAuB;CAC7C,CAAC;AAEF,SAAgB,kBAAkB,CAAC,WAAqB;IACtD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACnF,IAAI,WAAW,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChF,IAAI,WAAW,EAAE,CAAC;YAChB,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QAED,qDAAqD;QACrD,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAED,+BAA+B;IAC/B,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAEpE,OAAO;QACL,IAAI;QACJ,SAAS;QACT,YAAY;QACZ,SAAS;KACV,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAc,EACd,SAAmB,EACnB,YAAsB;IAEtB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,4BAA4B;IAC5B,MAAM,WAAW,GAAG,CAAC,CAAC;IACtB,MAAM,aAAa,GAAG,EAAE,CAAC;IACzB,MAAM,gBAAgB,GAAG,EAAE,CAAC;IAE5B,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;IAC9E,MAAM,WAAW,GACf,IAAI,CAAC,MAAM,GAAG,WAAW;QACzB,YAAY,CAAC,MAAM,GAAG,aAAa;QACnC,SAAS,CAAC,MAAM,GAAG,gBAAgB,CAAC;IAEtC,oEAAoE;IACpE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAElE,2DAA2D;IAC3D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,oDAAoD;IACpD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-analyzer.test.d.ts","sourceRoot":"","sources":["../../src/checker/permission-analyzer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const permission_analyzer_1 = require("./permission-analyzer");
|
|
5
|
+
(0, vitest_1.describe)('analyzePermissions', () => {
|
|
6
|
+
(0, vitest_1.it)('categorizes safe permissions', () => {
|
|
7
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['messages:read', 'config:read']);
|
|
8
|
+
(0, vitest_1.expect)(result.safe).toContain('messages:read');
|
|
9
|
+
(0, vitest_1.expect)(result.safe).toContain('config:read');
|
|
10
|
+
(0, vitest_1.expect)(result.dangerous).toHaveLength(0);
|
|
11
|
+
(0, vitest_1.expect)(result.riskScore).toBeLessThan(30);
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.it)('categorizes dangerous permissions', () => {
|
|
14
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['shell:execute', 'filesystem:*', 'network:*']);
|
|
15
|
+
(0, vitest_1.expect)(result.dangerous).toContain('shell:execute');
|
|
16
|
+
(0, vitest_1.expect)(result.dangerous).toContain('filesystem:*');
|
|
17
|
+
(0, vitest_1.expect)(result.dangerous).toContain('network:*');
|
|
18
|
+
(0, vitest_1.expect)(result.riskScore).toBeGreaterThan(70);
|
|
19
|
+
});
|
|
20
|
+
(0, vitest_1.it)('categorizes review-needed permissions', () => {
|
|
21
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['filesystem:~/Documents', 'network:api.example.com']);
|
|
22
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('filesystem:~/Documents');
|
|
23
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('network:api.example.com');
|
|
24
|
+
(0, vitest_1.expect)(result.riskScore).toBeGreaterThan(30);
|
|
25
|
+
(0, vitest_1.expect)(result.riskScore).toBeLessThan(70);
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)('flags wildcard permissions as dangerous', () => {
|
|
28
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['mcp:*']);
|
|
29
|
+
(0, vitest_1.expect)(result.dangerous).toContain('mcp:*');
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('returns empty arrays for no permissions', () => {
|
|
32
|
+
const result = (0, permission_analyzer_1.analyzePermissions)([]);
|
|
33
|
+
(0, vitest_1.expect)(result.safe).toHaveLength(0);
|
|
34
|
+
(0, vitest_1.expect)(result.dangerous).toHaveLength(0);
|
|
35
|
+
(0, vitest_1.expect)(result.reviewNeeded).toHaveLength(0);
|
|
36
|
+
(0, vitest_1.expect)(result.riskScore).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.it)('calculates risk score based on permission severity', () => {
|
|
39
|
+
const safeOnly = (0, permission_analyzer_1.analyzePermissions)(['messages:read']);
|
|
40
|
+
const mixed = (0, permission_analyzer_1.analyzePermissions)(['messages:read', 'filesystem:~/Downloads']);
|
|
41
|
+
const dangerous = (0, permission_analyzer_1.analyzePermissions)(['shell:execute', 'filesystem:*']);
|
|
42
|
+
(0, vitest_1.expect)(safeOnly.riskScore).toBeLessThan(mixed.riskScore);
|
|
43
|
+
(0, vitest_1.expect)(mixed.riskScore).toBeLessThan(dangerous.riskScore);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.describe)('permission patterns', () => {
|
|
47
|
+
(0, vitest_1.it)('recognizes shell permissions as dangerous', () => {
|
|
48
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['shell:execute', 'shell:read']);
|
|
49
|
+
(0, vitest_1.expect)(result.dangerous).toContain('shell:execute');
|
|
50
|
+
(0, vitest_1.expect)(result.dangerous).toContain('shell:read');
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)('recognizes broad filesystem access as dangerous', () => {
|
|
53
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['filesystem:*', 'filesystem:/', 'filesystem:~']);
|
|
54
|
+
result.dangerous.forEach((p) => {
|
|
55
|
+
(0, vitest_1.expect)(p).toMatch(/^filesystem:/);
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.expect)(result.dangerous.length).toBe(3);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('recognizes scoped filesystem access as review-needed', () => {
|
|
60
|
+
const result = (0, permission_analyzer_1.analyzePermissions)([
|
|
61
|
+
'filesystem:~/Documents',
|
|
62
|
+
'filesystem:~/.config/myapp',
|
|
63
|
+
]);
|
|
64
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('filesystem:~/Documents');
|
|
65
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('filesystem:~/.config/myapp');
|
|
66
|
+
(0, vitest_1.expect)(result.dangerous).toHaveLength(0);
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)('recognizes broad network access as dangerous', () => {
|
|
69
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['network:*']);
|
|
70
|
+
(0, vitest_1.expect)(result.dangerous).toContain('network:*');
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.it)('recognizes scoped network access as review-needed', () => {
|
|
73
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['network:api.github.com', 'network:example.com']);
|
|
74
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('network:api.github.com');
|
|
75
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('network:example.com');
|
|
76
|
+
});
|
|
77
|
+
(0, vitest_1.it)('recognizes mcp wildcard as dangerous', () => {
|
|
78
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['mcp:*']);
|
|
79
|
+
(0, vitest_1.expect)(result.dangerous).toContain('mcp:*');
|
|
80
|
+
});
|
|
81
|
+
(0, vitest_1.it)('recognizes specific mcp access as review-needed', () => {
|
|
82
|
+
const result = (0, permission_analyzer_1.analyzePermissions)(['mcp:github', 'mcp:filesystem']);
|
|
83
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('mcp:github');
|
|
84
|
+
(0, vitest_1.expect)(result.reviewNeeded).toContain('mcp:filesystem');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=permission-analyzer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-analyzer.test.js","sourceRoot":"","sources":["../../src/checker/permission-analyzer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publisher verification via DNS TXT records
|
|
3
|
+
*
|
|
4
|
+
* Publishers can verify ownership by adding a TXT record to their domain:
|
|
5
|
+
* - hackmyagent-verify=<publisher-name>
|
|
6
|
+
* - hackmyagent-publisher=<publisher-name>
|
|
7
|
+
* - opena2a-verify=<publisher-name>
|
|
8
|
+
*
|
|
9
|
+
* The record can be at:
|
|
10
|
+
* - The root domain (e.g., TXT @ for publisher.dev)
|
|
11
|
+
* - A _hackmyagent subdomain (e.g., TXT _hackmyagent.publisher.dev)
|
|
12
|
+
*/
|
|
13
|
+
export type VerificationMethod = 'dns' | 'github' | 'none';
|
|
14
|
+
export interface PublisherVerification {
|
|
15
|
+
verified: boolean;
|
|
16
|
+
method: VerificationMethod;
|
|
17
|
+
domain?: string;
|
|
18
|
+
txtRecord?: string;
|
|
19
|
+
verifiedAt?: Date;
|
|
20
|
+
failureReason?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface VerifyOptions {
|
|
23
|
+
mockDnsRecords?: Record<string, string[]>;
|
|
24
|
+
registryDomains?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Look up TXT records for a domain
|
|
28
|
+
*/
|
|
29
|
+
export declare function lookupDnsTxt(domain: string): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Verify a publisher's identity via DNS TXT records
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyPublisher(publisherName: string, options?: VerifyOptions): Promise<PublisherVerification>;
|
|
34
|
+
//# sourceMappingURL=publisher-verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publisher-verifier.d.ts","sourceRoot":"","sources":["../../src/checker/publisher-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAaD;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CASpE;AAuED;;GAEG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,qBAAqB,CAAC,CA0BhC"}
|