trusta 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Trusta (trusta-dev)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # trusta
2
+
3
+ [![npm version](https://img.shields.io/npm/v/trusta)](https://www.npmjs.com/package/trusta)
4
+ [![CI](https://github.com/trusta-dev/trusta-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/trusta-dev/trusta-cli/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ Generate your trust page in minutes.
8
+
9
+ ```bash
10
+ npx trusta init
11
+ ```
12
+
13
+ ## What it does
14
+
15
+ 1. Detects your project name, GitHub repo, and framework
16
+ 2. Creates a Trusta workspace and project at [trusta.dev](https://trusta.dev)
17
+ 3. Runs a local security scan across your codebase:
18
+ - Hardcoded secrets (API keys, tokens, credentials)
19
+ - Supabase RLS bypass vulnerabilities
20
+ - Exposed admin routes with client-side auth checks
21
+ - Unprotected API endpoints
22
+ 4. Submits findings as evidence — they contribute to your public trust score
23
+ 5. Links your GitHub repo so every push triggers an automatic re-scan
24
+ 6. Outputs a ready-to-paste GitHub Actions snippet
25
+
26
+ ## Requirements
27
+
28
+ - Node.js 18 or later
29
+ - A [Trusta](https://trusta.dev) account (free)
30
+
31
+ ## Usage
32
+
33
+ ```bash
34
+ npx trusta init
35
+ ```
36
+
37
+ You'll be prompted for:
38
+ 1. Your API token — get it at [app.trusta.dev/app/settings/tokens](https://app.trusta.dev/app/settings/tokens)
39
+ 2. Workspace name (your company or app name)
40
+ 3. Project name
41
+
42
+ ## Environment variables
43
+
44
+ | Variable | Description |
45
+ |---|---|
46
+ | `TRUSTA_API_TOKEN` | Skip the token prompt in CI |
47
+ | `TRUSTA_API_URL` | Override API base URL (default: `https://api.trusta.dev`) |
48
+ | `TRUSTA_APP_URL` | Override app base URL (default: `https://app.trusta.dev`) |
49
+
50
+ ## How the security score works
51
+
52
+ Each scan checks your codebase against four rules. Findings map directly to trust controls on your public trust page:
53
+
54
+ | Rule | Trust control |
55
+ |---|---|
56
+ | No hardcoded secrets | `security.no_hardcoded_secrets` |
57
+ | No RLS bypass | `security.rls_policies_enforced` |
58
+ | No exposed admin routes | `security.no_exposed_admin_routes` |
59
+ | No unprotected API endpoints | `security.no_unprotected_api_routes` |
60
+
61
+ Security contributes 25% of the overall trust score.
62
+
63
+ ## Contributing
64
+
65
+ See [CONTRIBUTING.md](CONTRIBUTING.md) — adding new scanning rules is a great first contribution.
66
+
67
+ ## Security
68
+
69
+ See [SECURITY.md](SECURITY.md) for how to report vulnerabilities responsibly.
70
+
71
+ ## License
72
+
73
+ [MIT](LICENSE) © [Trusta](https://trusta.dev)
package/dist/api.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ export interface CliApiTransport {
2
+ readonly baseUrl: string;
3
+ readonly token: string;
4
+ }
5
+ export interface BootstrapResult {
6
+ organization: {
7
+ id: string;
8
+ name: string;
9
+ };
10
+ project: {
11
+ id: string;
12
+ name: string;
13
+ slug: string;
14
+ };
15
+ }
16
+ export interface CollectorResult {
17
+ collector: {
18
+ id: string;
19
+ name: string;
20
+ };
21
+ secret: {
22
+ value: string;
23
+ };
24
+ }
25
+ export declare function bootstrapWorkspace(transport: CliApiTransport, input: {
26
+ workspaceName: string;
27
+ projectName: string;
28
+ }): Promise<BootstrapResult>;
29
+ export declare function createCollector(transport: CliApiTransport, projectId: string, name: string): Promise<CollectorResult>;
30
+ export interface IngestEvidenceInput {
31
+ readonly projectId: string;
32
+ readonly evidenceType: string;
33
+ readonly sourceType: string;
34
+ readonly sourceRef: string;
35
+ readonly observedAt: string;
36
+ readonly payload: unknown;
37
+ readonly metadataJson?: unknown;
38
+ }
39
+ export declare function ingestEvidence(collectorTransport: CliApiTransport, input: IngestEvidenceInput): Promise<{
40
+ evidenceRecordId: string;
41
+ }>;
42
+ export declare function registerProjectRepo(transport: CliApiTransport, projectId: string, repoUrl: string): Promise<{
43
+ id: string;
44
+ projectId: string;
45
+ repoUrl: string;
46
+ createdAt: string;
47
+ }>;
48
+ export declare function getMe(transport: CliApiTransport): Promise<{
49
+ user: {
50
+ id: string;
51
+ name: string;
52
+ };
53
+ }>;
54
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAmCD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3B;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,eAAe,CAAC,CAQ1B;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAsB,cAAc,CAClC,kBAAkB,EAAE,eAAe,EACnC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAC,CAOvC;AAED,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhF;AAED,wBAAsB,KAAK,CACzB,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CAEjD"}
package/dist/api.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bootstrapWorkspace = bootstrapWorkspace;
4
+ exports.createCollector = createCollector;
5
+ exports.ingestEvidence = ingestEvidence;
6
+ exports.registerProjectRepo = registerProjectRepo;
7
+ exports.getMe = getMe;
8
+ async function apiRequest(transport, method, path, body) {
9
+ const init = {
10
+ method,
11
+ headers: {
12
+ 'Content-Type': 'application/json',
13
+ Authorization: `Bearer ${transport.token}`,
14
+ },
15
+ };
16
+ if (body !== undefined) {
17
+ init.body = JSON.stringify(body);
18
+ }
19
+ const response = await fetch(`${transport.baseUrl}${path}`, init);
20
+ const data = (await response.json());
21
+ if (!response.ok) {
22
+ const errorData = data;
23
+ const message = errorData.error?.message ?? `HTTP ${response.status}`;
24
+ throw new Error(message);
25
+ }
26
+ return data;
27
+ }
28
+ async function bootstrapWorkspace(transport, input) {
29
+ const result = await apiRequest(transport, 'POST', '/onboarding/bootstrap', input);
30
+ return result;
31
+ }
32
+ async function createCollector(transport, projectId, name) {
33
+ return apiRequest(transport, 'POST', `/projects/${projectId}/collectors`, {
34
+ name,
35
+ allowedActions: ['evidence:write', 'heartbeat:write'],
36
+ });
37
+ }
38
+ async function ingestEvidence(collectorTransport, input) {
39
+ return apiRequest(collectorTransport, 'POST', '/ingest/evidence', input);
40
+ }
41
+ async function registerProjectRepo(transport, projectId, repoUrl) {
42
+ return apiRequest(transport, 'POST', `/projects/${projectId}/repos`, { repoUrl });
43
+ }
44
+ async function getMe(transport) {
45
+ return apiRequest(transport, 'GET', '/me');
46
+ }
47
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";;AAgDA,gDAWC;AAED,0CASC;AAYD,wCAUC;AAED,kDAMC;AAED,sBAIC;AAjGD,KAAK,UAAU,UAAU,CACvB,SAA0B,EAC1B,MAAgC,EAChC,IAAY,EACZ,IAAc;IAEd,MAAM,IAAI,GAAgB;QACxB,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,SAAS,CAAC,KAAK,EAAE;SAC3C;KACF,CAAC;IACF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAElE,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAiB,CAAC;IAErD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,IAAgB,CAAC;QACnC,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,IAAS,CAAC;AACnB,CAAC;AAYM,KAAK,UAAU,kBAAkB,CACtC,SAA0B,EAC1B,KAAqD;IAErD,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,SAAS,EACT,MAAM,EACN,uBAAuB,EACvB,KAAK,CACN,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,eAAe,CACnC,SAA0B,EAC1B,SAAiB,EACjB,IAAY;IAEZ,OAAO,UAAU,CAAkB,SAAS,EAAE,MAAM,EAAE,aAAa,SAAS,aAAa,EAAE;QACzF,IAAI;QACJ,cAAc,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;KACtD,CAAC,CAAC;AACL,CAAC;AAYM,KAAK,UAAU,cAAc,CAClC,kBAAmC,EACnC,KAA0B;IAE1B,OAAO,UAAU,CACf,kBAAkB,EAClB,MAAM,EACN,kBAAkB,EAClB,KAAK,CACN,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,mBAAmB,CACvC,SAA0B,EAC1B,SAAiB,EACjB,OAAe;IAEf,OAAO,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,SAAS,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;AACpF,CAAC;AAEM,KAAK,UAAU,KAAK,CACzB,SAA0B;IAE1B,OAAO,UAAU,CAAyC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function init(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAuBA,wBAAsB,IAAI,kBAiJzB"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.init = init;
4
+ const detect_1 = require("../detect");
5
+ const api_1 = require("../api");
6
+ const scanner_1 = require("../scanner");
7
+ const output_1 = require("../output");
8
+ const prompt_1 = require("../prompt");
9
+ const DEFAULT_API_URL = 'https://api.trusta.dev';
10
+ const DEFAULT_APP_URL = 'https://app.trusta.dev';
11
+ async function init() {
12
+ (0, output_1.printBanner)();
13
+ const detection = (0, detect_1.detectProject)();
14
+ const prompter = (0, prompt_1.createPrompter)();
15
+ try {
16
+ // Resolve API base URL
17
+ const apiUrl = (process.env['TRUSTA_API_URL'] ?? DEFAULT_API_URL).replace(/\/$/, '');
18
+ const appUrl = (process.env['TRUSTA_APP_URL'] ?? DEFAULT_APP_URL).replace(/\/$/, '');
19
+ // Resolve API token
20
+ let token = process.env['TRUSTA_API_TOKEN'] ?? '';
21
+ if (!token) {
22
+ (0, output_1.printStep)('Sign in at ' + appUrl + '/app/settings/tokens to get your API token.');
23
+ token = await prompter.ask('Paste your API token');
24
+ if (!token) {
25
+ throw new Error('API token is required. Set TRUSTA_API_TOKEN or enter it when prompted.');
26
+ }
27
+ }
28
+ const transport = { baseUrl: apiUrl, token };
29
+ // Workspace name
30
+ const defaultWorkspaceName = detection.projectName
31
+ ? toTitleCase(detection.projectName)
32
+ : undefined;
33
+ (0, output_1.printStep)('Name your workspace (your company or app name).');
34
+ const workspaceName = await prompter.ask('Workspace name', defaultWorkspaceName);
35
+ if (!workspaceName) {
36
+ throw new Error('Workspace name is required.');
37
+ }
38
+ // Project name
39
+ const defaultProjectName = detection.projectName ?? undefined;
40
+ const projectName = await prompter.ask('First project name', defaultProjectName);
41
+ if (!projectName) {
42
+ throw new Error('Project name is required.');
43
+ }
44
+ (0, output_1.printDivider)();
45
+ // Bootstrap workspace + project
46
+ (0, output_1.printStep)('Creating workspace and project...');
47
+ const { organization, project } = await (0, api_1.bootstrapWorkspace)(transport, {
48
+ workspaceName,
49
+ projectName,
50
+ });
51
+ (0, output_1.printSuccess)(`Workspace "${organization.name}" created`);
52
+ (0, output_1.printSuccess)(`Project "${project.name}" created`);
53
+ // Create GitHub Actions collector
54
+ (0, output_1.printStep)('Creating collector credential for GitHub Actions...');
55
+ const collector = await (0, api_1.createCollector)(transport, project.id, 'github-actions');
56
+ (0, output_1.printSuccess)('Collector "github-actions" created');
57
+ // Register the GitHub repo URL so push webhooks resolve to this project
58
+ if (detection.githubRepoUrl) {
59
+ try {
60
+ await (0, api_1.registerProjectRepo)(transport, project.id, detection.githubRepoUrl);
61
+ (0, output_1.printSuccess)(`GitHub repo linked: ${detection.githubRepoUrl}`);
62
+ }
63
+ catch {
64
+ (0, output_1.printWarning)('Could not link GitHub repo — you can add it later in the dashboard.');
65
+ }
66
+ }
67
+ (0, output_1.printDivider)();
68
+ // Run local security scan and push findings as evidence
69
+ (0, output_1.printStep)('Scanning local files for security issues...');
70
+ const cwd = process.cwd();
71
+ try {
72
+ const scanResult = await (0, scanner_1.scanLocalDirectory)(cwd);
73
+ const { summary, findings } = scanResult;
74
+ // Use collector secret as bearer token for evidence ingest
75
+ const collectorTransport = {
76
+ baseUrl: apiUrl,
77
+ token: collector.secret.value,
78
+ };
79
+ await (0, api_1.ingestEvidence)(collectorTransport, {
80
+ projectId: project.id,
81
+ evidenceType: 'security_scan',
82
+ sourceType: 'local_fs',
83
+ sourceRef: cwd,
84
+ observedAt: new Date().toISOString(),
85
+ payload: { findings: findings.slice(0, 100) }, // cap payload size
86
+ metadataJson: summary,
87
+ });
88
+ // Print scan summary
89
+ if (summary.criticalCount > 0 || summary.highCount > 0) {
90
+ (0, output_1.printWarning)(`Security scan found ${summary.criticalCount} critical, ${summary.highCount} high, ` +
91
+ `${summary.mediumCount} medium issues across ${summary.filesScanned} files.`);
92
+ const topFindings = findings
93
+ .filter((f) => f.severity === 'critical' || f.severity === 'high')
94
+ .slice(0, 5);
95
+ for (const finding of topFindings) {
96
+ process.stdout.write(` [${finding.severity.toUpperCase()}] ${finding.filePath}:${finding.lineNumber} — ${finding.ruleId}\n`);
97
+ }
98
+ if (findings.length > 5) {
99
+ process.stdout.write(` ... and ${findings.length - 5} more. See dashboard for details.\n`);
100
+ }
101
+ }
102
+ else {
103
+ (0, output_1.printSuccess)(`Security scan passed — ${summary.filesScanned} files scanned, score: ${summary.securityScore}/100`);
104
+ }
105
+ }
106
+ catch {
107
+ (0, output_1.printWarning)('Security scan could not complete — you can trigger one from the dashboard.');
108
+ }
109
+ // Output summary
110
+ const trustUrl = `${DEFAULT_APP_URL}/trust/${project.slug}`;
111
+ (0, output_1.printSuccess)('Setup complete!');
112
+ (0, output_1.printDivider)();
113
+ (0, output_1.printInfo)('Trust page:', trustUrl);
114
+ (0, output_1.printInfo)('Dashboard:', `${appUrl}/app`);
115
+ (0, output_1.printDivider)();
116
+ // GitHub Actions YAML snippet
117
+ process.stdout.write(' Add this to your GitHub Actions workflow:\n');
118
+ (0, output_1.printCode)(buildGitHubActionsYaml(collector.secret.value, apiUrl, project.id, detection.githubRepoUrl ?? undefined));
119
+ // Agent setup prompt
120
+ if (detection.framework) {
121
+ process.stdout.write(` Detected framework: ${detection.framework}\n\n`);
122
+ }
123
+ process.stdout.write(' To configure Trusta with an AI agent (Claude Code, Cursor, Windsurf):\n');
124
+ (0, output_1.printCode)(buildAgentPrompt(collector.secret.value, apiUrl, project.id));
125
+ process.stdout.write(' Save TRUSTA_COLLECTOR_SECRET as a GitHub Actions secret to keep it out of your repo.\n\n');
126
+ }
127
+ finally {
128
+ prompter.close();
129
+ }
130
+ }
131
+ function toTitleCase(name) {
132
+ return name
133
+ .replace(/[-_]/g, ' ')
134
+ .replace(/\b\w/g, (c) => c.toUpperCase());
135
+ }
136
+ function buildGitHubActionsYaml(secret, apiUrl, projectId, repoUrl) {
137
+ const repoLine = repoUrl ? ` repo_url: '${repoUrl}'\n` : '';
138
+ return `- name: Report to Trusta
139
+ uses: trusta/trusta-action@v1
140
+ with:
141
+ api_url: '${apiUrl}'
142
+ project_id: '${projectId}'
143
+ ${repoLine} env:
144
+ TRUSTA_COLLECTOR_SECRET: \${{ secrets.TRUSTA_COLLECTOR_SECRET }}
145
+ # Secret value (save as GitHub Actions secret):
146
+ # ${secret}`;
147
+ }
148
+ function buildAgentPrompt(secret, apiUrl, projectId) {
149
+ return `Set up Trusta evidence collection for this project.
150
+ API URL: ${apiUrl}
151
+ Project ID: ${projectId}
152
+ Collector secret: ${secret}
153
+ Add TRUSTA_COLLECTOR_SECRET=${secret} to CI environment variables.
154
+ Then call POST ${apiUrl}/ingest/evidence with Bearer auth on each deploy.`;
155
+ }
156
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface ProjectDetection {
2
+ readonly projectName: string | null;
3
+ readonly githubRepoUrl: string | null;
4
+ readonly framework: string | null;
5
+ }
6
+ export declare function detectProject(cwd?: string): ProjectDetection;
7
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAsB,GAAG,gBAAgB,CAK3E"}
package/dist/detect.js ADDED
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectProject = detectProject;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_child_process_1 = require("node:child_process");
6
+ function detectProject(cwd = process.cwd()) {
7
+ const projectName = detectProjectName(cwd);
8
+ const githubRepoUrl = detectGitHubRepoUrl(cwd);
9
+ const framework = detectFramework(cwd);
10
+ return { projectName, githubRepoUrl, framework };
11
+ }
12
+ function detectProjectName(cwd) {
13
+ const pkgPath = `${cwd}/package.json`;
14
+ if ((0, node_fs_1.existsSync)(pkgPath)) {
15
+ try {
16
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, 'utf8'));
17
+ if (typeof pkg.name === 'string' && pkg.name.length > 0) {
18
+ return pkg.name.replace(/^@[^/]+\//, '');
19
+ }
20
+ }
21
+ catch {
22
+ // ignore
23
+ }
24
+ }
25
+ return cwd.split('/').at(-1) ?? null;
26
+ }
27
+ function detectGitHubRepoUrl(cwd) {
28
+ try {
29
+ const remote = (0, node_child_process_1.execSync)('git remote get-url origin', {
30
+ cwd,
31
+ stdio: ['pipe', 'pipe', 'pipe'],
32
+ })
33
+ .toString()
34
+ .trim();
35
+ // SSH: git@github.com:owner/repo.git
36
+ const sshMatch = /^git@github\.com:([^/]+\/[^.]+)/.exec(remote);
37
+ if (sshMatch?.[1]) {
38
+ return `https://github.com/${sshMatch[1]}`;
39
+ }
40
+ // HTTPS: https://github.com/owner/repo.git
41
+ const httpsMatch = /^https:\/\/github\.com\/([^/]+\/[^.]+)/.exec(remote);
42
+ if (httpsMatch?.[1]) {
43
+ return `https://github.com/${httpsMatch[1]}`;
44
+ }
45
+ }
46
+ catch {
47
+ // not a git repo or no remote
48
+ }
49
+ return null;
50
+ }
51
+ function detectFramework(cwd) {
52
+ const pkgPath = `${cwd}/package.json`;
53
+ if (!(0, node_fs_1.existsSync)(pkgPath))
54
+ return null;
55
+ try {
56
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, 'utf8'));
57
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
58
+ if ('next' in deps)
59
+ return 'Next.js';
60
+ if ('nuxt' in deps)
61
+ return 'Nuxt';
62
+ if ('remix' in deps || '@remix-run/node' in deps)
63
+ return 'Remix';
64
+ if ('astro' in deps)
65
+ return 'Astro';
66
+ if ('svelte' in deps)
67
+ return 'SvelteKit';
68
+ if ('react' in deps)
69
+ return 'React';
70
+ if ('vue' in deps)
71
+ return 'Vue';
72
+ if ('express' in deps)
73
+ return 'Express';
74
+ if ('fastify' in deps)
75
+ return 'Fastify';
76
+ }
77
+ catch {
78
+ // ignore
79
+ }
80
+ if ((0, node_fs_1.existsSync)(`${cwd}/requirements.txt`) || (0, node_fs_1.existsSync)(`${cwd}/pyproject.toml`)) {
81
+ return 'Python';
82
+ }
83
+ if ((0, node_fs_1.existsSync)(`${cwd}/go.mod`))
84
+ return 'Go';
85
+ if ((0, node_fs_1.existsSync)(`${cwd}/Cargo.toml`))
86
+ return 'Rust';
87
+ return null;
88
+ }
89
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const init_1 = require("./commands/init");
5
+ const [, , command = 'init'] = process.argv;
6
+ if (command === 'init') {
7
+ (0, init_1.init)().catch((error) => {
8
+ const message = error instanceof Error ? error.message : String(error);
9
+ process.stderr.write(`\nError: ${message}\n`);
10
+ process.exit(1);
11
+ });
12
+ }
13
+ else {
14
+ process.stderr.write(`Unknown command: ${command}\nUsage: npx trusta init\n`);
15
+ process.exit(1);
16
+ }
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,0CAAuC;AAEvC,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;AAE5C,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;IACvB,IAAA,WAAI,GAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC9B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,OAAO,IAAI,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,4BAA4B,CAAC,CAAC;IAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function printBanner(): void;
2
+ export declare function printStep(step: string): void;
3
+ export declare function printSuccess(message: string): void;
4
+ export declare function printWarning(message: string): void;
5
+ export declare function printInfo(label: string, value: string): void;
6
+ export declare function printCode(code: string): void;
7
+ export declare function printDivider(): void;
8
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAQA,wBAAgB,WAAW,SAE1B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,QAErC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,QAE3C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,QAE3C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAErD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,QAOrC;AAED,wBAAgB,YAAY,SAE3B"}
package/dist/output.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printBanner = printBanner;
4
+ exports.printStep = printStep;
5
+ exports.printSuccess = printSuccess;
6
+ exports.printWarning = printWarning;
7
+ exports.printInfo = printInfo;
8
+ exports.printCode = printCode;
9
+ exports.printDivider = printDivider;
10
+ const RESET = '\x1b[0m';
11
+ const BOLD = '\x1b[1m';
12
+ const DIM = '\x1b[2m';
13
+ const GREEN = '\x1b[32m';
14
+ const CYAN = '\x1b[36m';
15
+ const YELLOW = '\x1b[33m';
16
+ const BLUE = '\x1b[34m';
17
+ function printBanner() {
18
+ process.stdout.write(`\n${BOLD}${CYAN} trusta${RESET} — generate your trust page in minutes\n\n`);
19
+ }
20
+ function printStep(step) {
21
+ process.stdout.write(`${DIM}→${RESET} ${step}\n`);
22
+ }
23
+ function printSuccess(message) {
24
+ process.stdout.write(`${GREEN}✓${RESET} ${message}\n`);
25
+ }
26
+ function printWarning(message) {
27
+ process.stdout.write(`${YELLOW}⚠${RESET} ${message}\n`);
28
+ }
29
+ function printInfo(label, value) {
30
+ process.stdout.write(` ${DIM}${label}${RESET} ${BOLD}${value}${RESET}\n`);
31
+ }
32
+ function printCode(code) {
33
+ const lines = code.split('\n');
34
+ process.stdout.write(`\n${DIM}${'─'.repeat(60)}${RESET}\n`);
35
+ for (const line of lines) {
36
+ process.stdout.write(` ${BLUE}${line}${RESET}\n`);
37
+ }
38
+ process.stdout.write(`${DIM}${'─'.repeat(60)}${RESET}\n\n`);
39
+ }
40
+ function printDivider() {
41
+ process.stdout.write(`\n${DIM}${'─'.repeat(60)}${RESET}\n\n`);
42
+ }
43
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":";;AAQA,kCAEC;AAED,8BAEC;AAED,oCAEC;AAED,oCAEC;AAED,8BAEC;AAED,8BAOC;AAED,oCAEC;AAvCD,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,KAAK,GAAG,UAAU,CAAC;AACzB,MAAM,IAAI,GAAG,UAAU,CAAC;AACxB,MAAM,MAAM,GAAG,UAAU,CAAC;AAC1B,MAAM,IAAI,GAAG,UAAU,CAAC;AAExB,SAAgB,WAAW;IACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,IAAI,WAAW,KAAK,6CAA6C,CAAC,CAAC;AACtG,CAAC;AAED,SAAgB,SAAS,CAAC,IAAY;IACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe;IAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe;IAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,SAAgB,SAAS,CAAC,KAAa,EAAE,KAAa;IACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,KAAK,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,SAAgB,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IAC5D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,SAAgB,YAAY;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function createPrompter(): {
2
+ ask: (question: string, defaultValue?: string) => Promise<string>;
3
+ close: () => void;
4
+ };
5
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc;oBAMC,MAAM,iBAAiB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;;EAc7E"}
package/dist/prompt.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPrompter = createPrompter;
4
+ const node_readline_1 = require("node:readline");
5
+ function createPrompter() {
6
+ const rl = (0, node_readline_1.createInterface)({
7
+ input: process.stdin,
8
+ output: process.stdout,
9
+ });
10
+ async function ask(question, defaultValue) {
11
+ const suffix = defaultValue ? ` [${defaultValue}]` : '';
12
+ return new Promise((resolve) => {
13
+ rl.question(` ${question}${suffix}: `, (answer) => {
14
+ resolve(answer.trim() || defaultValue || '');
15
+ });
16
+ });
17
+ }
18
+ function close() {
19
+ rl.close();
20
+ }
21
+ return { ask, close };
22
+ }
23
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":";;AAEA,wCAoBC;AAtBD,iDAAgD;AAEhD,SAAgB,cAAc;IAC5B,MAAM,EAAE,GAAG,IAAA,+BAAe,EAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,KAAK,UAAU,GAAG,CAAC,QAAgB,EAAE,YAAqB;QACxD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,EAAE,CAAC,QAAQ,CAAC,KAAK,QAAQ,GAAG,MAAM,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE;gBACjD,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,YAAY,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,KAAK;QACZ,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AACxB,CAAC"}
@@ -0,0 +1,27 @@
1
+ export type SecurityFindingSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
2
+ export interface SecurityFinding {
3
+ readonly findingId: string;
4
+ readonly ruleId: string;
5
+ readonly severity: SecurityFindingSeverity;
6
+ readonly filePath: string;
7
+ readonly lineNumber: number;
8
+ readonly snippet: string;
9
+ readonly fix: string;
10
+ }
11
+ export interface LocalScanSummary {
12
+ readonly criticalCount: number;
13
+ readonly highCount: number;
14
+ readonly mediumCount: number;
15
+ readonly lowCount: number;
16
+ readonly rlsBypassCount: number;
17
+ readonly apiAuthCount: number;
18
+ readonly securityScore: number;
19
+ readonly filesScanned: number;
20
+ }
21
+ export interface LocalScanResult {
22
+ readonly findings: SecurityFinding[];
23
+ readonly summary: LocalScanSummary;
24
+ }
25
+ /** Scans local source files in `dir` and returns findings + summary. No network I/O. */
26
+ export declare function scanLocalDirectory(dir: string): Promise<LocalScanResult>;
27
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;CACpC;AAwND,wFAAwF;AACxF,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA8C9E"}
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scanLocalDirectory = scanLocalDirectory;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
6
+ // --- Scanning rules (mirrors packages/domain — pure, no I/O) ---
7
+ const SECRET_PATTERNS = [
8
+ {
9
+ ruleId: 'hardcoded_stripe_secret_key',
10
+ pattern: /\bsk_(live|test)_[a-zA-Z0-9]{24,}\b/g,
11
+ severity: 'critical',
12
+ fix: 'Move this Stripe secret key to an environment variable (e.g. process.env.STRIPE_SECRET_KEY) and add it to your .env file. Never commit secret keys to source control.',
13
+ },
14
+ {
15
+ ruleId: 'hardcoded_supabase_service_role_key',
16
+ pattern: /\beyJ[a-zA-Z0-9+/]{50,}={0,2}\b/g,
17
+ severity: 'critical',
18
+ fix: 'Move this Supabase service role key to a server-only environment variable. Never use the service role key in client-side code — it bypasses all Row Level Security policies.',
19
+ },
20
+ {
21
+ ruleId: 'hardcoded_openai_api_key',
22
+ pattern: /\bsk-(?:proj-)?[a-zA-Z0-9]{32,}\b/g,
23
+ severity: 'critical',
24
+ fix: 'Move this OpenAI API key to an environment variable (e.g. process.env.OPENAI_API_KEY). Exposed API keys can result in unauthorized charges.',
25
+ },
26
+ {
27
+ ruleId: 'hardcoded_anthropic_api_key',
28
+ pattern: /\bsk-ant-[a-zA-Z0-9_-]{32,}\b/g,
29
+ severity: 'critical',
30
+ fix: 'Move this Anthropic API key to an environment variable (e.g. process.env.ANTHROPIC_API_KEY). Exposed API keys can result in unauthorized charges.',
31
+ },
32
+ {
33
+ ruleId: 'hardcoded_aws_secret_access_key',
34
+ pattern: /(?:AWS_SECRET_ACCESS_KEY|aws_secret_access_key)\s*[=:]\s*["']?([a-zA-Z0-9/+]{40})["']?/g,
35
+ severity: 'critical',
36
+ fix: 'Remove this AWS secret access key from source code. Use IAM roles, environment variables, or AWS Secrets Manager instead.',
37
+ },
38
+ ];
39
+ const CLIENT_SIDE_PATH_PATTERNS = [
40
+ /^(src\/)?components\//,
41
+ /^(src\/)?pages\//,
42
+ /^(src\/)?app\//,
43
+ /^(src\/)?hooks\//,
44
+ /^(src\/)?lib\//,
45
+ /\.(tsx|jsx)$/,
46
+ ];
47
+ const SERVER_SIDE_PATH_EXCLUSIONS = [
48
+ /route\.(ts|js)$/,
49
+ /server\.(ts|js)$/,
50
+ /api\//,
51
+ /actions\.(ts|js)$/,
52
+ /middleware\.(ts|js)$/,
53
+ ];
54
+ function isClientSidePath(filePath) {
55
+ const isClientLike = CLIENT_SIDE_PATH_PATTERNS.some((p) => p.test(filePath));
56
+ const isServerExcluded = SERVER_SIDE_PATH_EXCLUSIONS.some((p) => p.test(filePath));
57
+ return isClientLike && !isServerExcluded;
58
+ }
59
+ function scanForHardcodedSecrets(fileContent, filePath) {
60
+ const findings = [];
61
+ const lines = fileContent.split('\n');
62
+ for (const rule of SECRET_PATTERNS) {
63
+ rule.pattern.lastIndex = 0;
64
+ let match;
65
+ while ((match = rule.pattern.exec(fileContent)) !== null) {
66
+ const before = fileContent.slice(0, match.index);
67
+ const lineNumber = before.split('\n').length;
68
+ const line = lines[lineNumber - 1] ?? '';
69
+ const snippet = line.trim().slice(0, 120);
70
+ findings.push({
71
+ findingId: `${rule.ruleId}:${filePath}:${lineNumber}`,
72
+ ruleId: rule.ruleId,
73
+ severity: rule.severity,
74
+ filePath,
75
+ lineNumber,
76
+ snippet,
77
+ fix: rule.fix,
78
+ });
79
+ }
80
+ rule.pattern.lastIndex = 0;
81
+ }
82
+ return findings;
83
+ }
84
+ function scanForRlsBypassVulnerabilities(fileContent, filePath) {
85
+ if (!isClientSidePath(filePath))
86
+ return [];
87
+ const findings = [];
88
+ const lines = fileContent.split('\n');
89
+ const serviceRolePattern = /createClient\s*\([^)]*(?:SERVICE_ROLE|service_role|serviceRole)[^)]*\)/g;
90
+ let match;
91
+ while ((match = serviceRolePattern.exec(fileContent)) !== null) {
92
+ const before = fileContent.slice(0, match.index);
93
+ const lineNumber = before.split('\n').length;
94
+ const snippet = (lines[lineNumber - 1] ?? '').trim().slice(0, 120);
95
+ findings.push({
96
+ findingId: `rls_bypass_client_service_role:${filePath}:${lineNumber}`,
97
+ ruleId: 'rls_bypass_client_service_role',
98
+ severity: 'critical',
99
+ filePath,
100
+ lineNumber,
101
+ snippet,
102
+ fix: 'Never use the Supabase service role key in client-side code. It bypasses all Row Level Security policies and exposes all your data. Use the anon key for client code and keep the service role key server-side only.',
103
+ });
104
+ }
105
+ return findings;
106
+ }
107
+ function scanForExposedAdminRoutes(fileContent, filePath) {
108
+ if (!isClientSidePath(filePath))
109
+ return [];
110
+ const findings = [];
111
+ const lines = fileContent.split('\n');
112
+ const localStorageAuthPattern = /localStorage\.getItem\s*\(\s*["'](?:role|isAdmin|admin|is_admin|userRole|user_role)["']\s*\)/g;
113
+ let match;
114
+ while ((match = localStorageAuthPattern.exec(fileContent)) !== null) {
115
+ const before = fileContent.slice(0, match.index);
116
+ const lineNumber = before.split('\n').length;
117
+ const snippet = (lines[lineNumber - 1] ?? '').trim().slice(0, 120);
118
+ findings.push({
119
+ findingId: `exposed_admin_route_localstorage:${filePath}:${lineNumber}`,
120
+ ruleId: 'exposed_admin_route_localstorage',
121
+ severity: 'high',
122
+ filePath,
123
+ lineNumber,
124
+ snippet,
125
+ fix: 'Do not use localStorage for admin access control. localStorage can be modified by any user in their browser. Implement server-side role checks using your auth provider (Supabase RLS, session middleware, etc.).',
126
+ });
127
+ }
128
+ return findings;
129
+ }
130
+ function scanForUnprotectedApiEndpoints(fileContent, filePath) {
131
+ if (!/(route\.(ts|js)|api\/|handler\.(ts|js))/.test(filePath))
132
+ return [];
133
+ const findings = [];
134
+ const lines = fileContent.split('\n');
135
+ const firstLines = lines.slice(0, 30).join('\n');
136
+ const hasAuthCheck = /\b(?:getServerSession|auth\(\)|verifyJwt|authenticate|requireAuth|withAuth|getSession|supabase\.auth|createServerClient)\b/.test(firstLines);
137
+ const exportedHandlerPattern = /export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|handler)\b/g;
138
+ let match;
139
+ while ((match = exportedHandlerPattern.exec(fileContent)) !== null) {
140
+ if (!hasAuthCheck) {
141
+ const before = fileContent.slice(0, match.index);
142
+ const lineNumber = before.split('\n').length;
143
+ const snippet = (lines[lineNumber - 1] ?? '').trim().slice(0, 120);
144
+ findings.push({
145
+ findingId: `unprotected_api_endpoint:${filePath}:${lineNumber}`,
146
+ ruleId: 'unprotected_api_endpoint',
147
+ severity: 'high',
148
+ filePath,
149
+ lineNumber,
150
+ snippet,
151
+ fix: 'Add authentication to this API route. Verify the user session at the start of the handler before processing any data.',
152
+ });
153
+ }
154
+ }
155
+ return findings;
156
+ }
157
+ function computeSecurityScore(findings) {
158
+ const weights = {
159
+ critical: 25,
160
+ high: 10,
161
+ medium: 3,
162
+ low: 1,
163
+ info: 0,
164
+ };
165
+ const penalty = findings.reduce((acc, f) => acc + (weights[f.severity] ?? 0), 0);
166
+ return Math.max(0, Math.min(100, 100 - penalty));
167
+ }
168
+ // --- Local directory walker ---
169
+ const SOURCE_EXTENSIONS = /\.(ts|tsx|js|jsx|mjs|cjs|py|rb|go|java|php|cs)$/;
170
+ const EXCLUDED_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'out', '.turbo', 'coverage']);
171
+ async function walkDir(dir, root) {
172
+ const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
173
+ const files = [];
174
+ for (const entry of entries) {
175
+ if (entry.name.startsWith('.') && entry.isDirectory())
176
+ continue;
177
+ if (entry.isDirectory() && EXCLUDED_DIRS.has(entry.name))
178
+ continue;
179
+ const fullPath = (0, node_path_1.join)(dir, entry.name);
180
+ if (entry.isDirectory()) {
181
+ const nested = await walkDir(fullPath, root);
182
+ files.push(...nested);
183
+ }
184
+ else if (entry.isFile() && SOURCE_EXTENSIONS.test(entry.name)) {
185
+ files.push(fullPath);
186
+ }
187
+ }
188
+ return files;
189
+ }
190
+ /** Scans local source files in `dir` and returns findings + summary. No network I/O. */
191
+ async function scanLocalDirectory(dir) {
192
+ const allFiles = await walkDir(dir, dir);
193
+ const findings = [];
194
+ await Promise.all(allFiles.map(async (absolutePath) => {
195
+ const relPath = (0, node_path_1.relative)(dir, absolutePath).replace(/\\/g, '/');
196
+ let content;
197
+ try {
198
+ content = await (0, promises_1.readFile)(absolutePath, 'utf8');
199
+ }
200
+ catch {
201
+ return;
202
+ }
203
+ const fileFindings = [
204
+ ...scanForHardcodedSecrets(content, relPath),
205
+ ...scanForRlsBypassVulnerabilities(content, relPath),
206
+ ...scanForExposedAdminRoutes(content, relPath),
207
+ ...scanForUnprotectedApiEndpoints(content, relPath),
208
+ ];
209
+ findings.push(...fileFindings);
210
+ }));
211
+ const criticalCount = findings.filter((f) => f.severity === 'critical').length;
212
+ const highCount = findings.filter((f) => f.severity === 'high').length;
213
+ const mediumCount = findings.filter((f) => f.severity === 'medium').length;
214
+ const lowCount = findings.filter((f) => f.severity === 'low').length;
215
+ const rlsBypassCount = findings.filter((f) => f.ruleId.startsWith('rls_bypass')).length;
216
+ const apiAuthCount = findings.filter((f) => f.ruleId.startsWith('unprotected_api')).length;
217
+ const securityScore = computeSecurityScore(findings);
218
+ return {
219
+ findings,
220
+ summary: {
221
+ criticalCount,
222
+ highCount,
223
+ mediumCount,
224
+ lowCount,
225
+ rlsBypassCount,
226
+ apiAuthCount,
227
+ securityScore,
228
+ filesScanned: allFiles.length,
229
+ },
230
+ };
231
+ }
232
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":";;AAwPA,gDA8CC;AAtSD,+CAAqD;AACrD,yCAA2C;AAgC3C,kEAAkE;AAElE,MAAM,eAAe,GAKhB;IACH;QACE,MAAM,EAAE,6BAA6B;QACrC,OAAO,EAAE,sCAAsC;QAC/C,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,uKAAuK;KAC7K;IACD;QACE,MAAM,EAAE,qCAAqC;QAC7C,OAAO,EAAE,kCAAkC;QAC3C,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,8KAA8K;KACpL;IACD;QACE,MAAM,EAAE,0BAA0B;QAClC,OAAO,EAAE,oCAAoC;QAC7C,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,6IAA6I;KACnJ;IACD;QACE,MAAM,EAAE,6BAA6B;QACrC,OAAO,EAAE,gCAAgC;QACzC,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,mJAAmJ;KACzJ;IACD;QACE,MAAM,EAAE,iCAAiC;QACzC,OAAO,EAAE,yFAAyF;QAClG,QAAQ,EAAE,UAAU;QACpB,GAAG,EAAE,2HAA2H;KACjI;CACF,CAAC;AAEF,MAAM,yBAAyB,GAAG;IAChC,uBAAuB;IACvB,kBAAkB;IAClB,gBAAgB;IAChB,kBAAkB;IAClB,gBAAgB;IAChB,cAAc;CACf,CAAC;AAEF,MAAM,2BAA2B,GAAG;IAClC,iBAAiB;IACjB,kBAAkB;IAClB,OAAO;IACP,mBAAmB;IACnB,sBAAsB;CACvB,CAAC;AAEF,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,YAAY,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7E,MAAM,gBAAgB,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnF,OAAO,YAAY,IAAI,CAAC,gBAAgB,CAAC;AAC3C,CAAC;AAED,SAAS,uBAAuB,CAAC,WAAmB,EAAE,QAAgB;IACpE,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,IAAI,KAA6B,CAAC;QAClC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACjD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC;gBACZ,SAAS,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,IAAI,UAAU,EAAE;gBACrD,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ;gBACR,UAAU;gBACV,OAAO;gBACP,GAAG,EAAE,IAAI,CAAC,GAAG;aACd,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,+BAA+B,CAAC,WAAmB,EAAE,QAAgB;IAC5E,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3C,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,kBAAkB,GAAG,yEAAyE,CAAC;IACrG,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC7C,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACnE,QAAQ,CAAC,IAAI,CAAC;YACZ,SAAS,EAAE,kCAAkC,QAAQ,IAAI,UAAU,EAAE;YACrE,MAAM,EAAE,gCAAgC;YACxC,QAAQ,EAAE,UAAU;YACpB,QAAQ;YACR,UAAU;YACV,OAAO;YACP,GAAG,EAAE,sNAAsN;SAC5N,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,yBAAyB,CAAC,WAAmB,EAAE,QAAgB;IACtE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3C,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,uBAAuB,GAC3B,+FAA+F,CAAC;IAClG,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpE,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC7C,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACnE,QAAQ,CAAC,IAAI,CAAC;YACZ,SAAS,EAAE,oCAAoC,QAAQ,IAAI,UAAU,EAAE;YACvE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,MAAM;YAChB,QAAQ;YACR,UAAU;YACV,OAAO;YACP,GAAG,EAAE,mNAAmN;SACzN,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,8BAA8B,CAAC,WAAmB,EAAE,QAAgB;IAC3E,IAAI,CAAC,yCAAyC,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzE,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEtC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,YAAY,GAChB,4HAA4H,CAAC,IAAI,CAC/H,UAAU,CACX,CAAC;IAEJ,MAAM,sBAAsB,GAAG,yEAAyE,CAAC;IACzG,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnE,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;YACjD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YAC7C,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACnE,QAAQ,CAAC,IAAI,CAAC;gBACZ,SAAS,EAAE,4BAA4B,QAAQ,IAAI,UAAU,EAAE;gBAC/D,MAAM,EAAE,0BAA0B;gBAClC,QAAQ,EAAE,MAAM;gBAChB,QAAQ;gBACR,UAAU;gBACV,OAAO;gBACP,GAAG,EAAE,uHAAuH;aAC7H,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,oBAAoB,CAAC,QAA2B;IACvD,MAAM,OAAO,GAA4C;QACvD,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;KACR,CAAC;IACF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,iCAAiC;AAEjC,MAAM,iBAAiB,GAAG,iDAAiD,CAAC;AAC5E,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAE/G,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC9C,MAAM,OAAO,GAAG,MAAM,IAAA,kBAAO,EAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QAChE,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAEnE,MAAM,QAAQ,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QACxB,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wFAAwF;AACjF,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,MAAM,OAAO,CAAC,GAAG,CACf,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE;QAClC,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,GAAG,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChE,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG;YACnB,GAAG,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC;YAC5C,GAAG,+BAA+B,CAAC,OAAO,EAAE,OAAO,CAAC;YACpD,GAAG,yBAAyB,CAAC,OAAO,EAAE,OAAO,CAAC;YAC9C,GAAG,8BAA8B,CAAC,OAAO,EAAE,OAAO,CAAC;SACpD,CAAC;QAEF,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IACjC,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC3E,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IACrE,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IACxF,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3F,MAAM,aAAa,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAErD,OAAO;QACL,QAAQ;QACR,OAAO,EAAE;YACP,aAAa;YACb,SAAS;YACT,WAAW;YACX,QAAQ;YACR,cAAc;YACd,YAAY;YACZ,aAAa;YACb,YAAY,EAAE,QAAQ,CAAC,MAAM;SAC9B;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "trusta",
3
+ "version": "0.1.0",
4
+ "description": "Generate your trust page in minutes — npx trusta init",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "trusta": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "typecheck": "tsc -p tsconfig.json --noEmit",
17
+ "lint": "eslint src --max-warnings=0",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "keywords": [
24
+ "trust",
25
+ "security",
26
+ "compliance",
27
+ "trusta"
28
+ ],
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/trusta-dev/trusta-cli.git"
32
+ },
33
+ "homepage": "https://trusta.dev",
34
+ "devDependencies": {
35
+ "@types/node": "^22.0.0",
36
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
37
+ "@typescript-eslint/parser": "^8.0.0",
38
+ "eslint": "^9.0.0",
39
+ "typescript": "^5.5.0"
40
+ }
41
+ }