saastore-port 0.1.1

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) 2026 saastore.ai
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,86 @@
1
+ # saastore-port
2
+
3
+ MCP server the seller runs locally to port their app onto saastore hosting.
4
+
5
+ The seller's IDE-side agent (Claude Code, Cursor, Cline, Zed, …) connects via
6
+ stdio. The seller's existing API key drives any LLM calls — saastore never
7
+ sees source or keys (see spec §7.1 in the saastore monorepo).
8
+
9
+ ## Status
10
+
11
+ All 8 tools shipped at PoC quality. Concierge first-seller work will surface
12
+ friction → polish iterations, but the surface is complete.
13
+
14
+ | Tool | Status | Tests |
15
+ | --- | --- | --- |
16
+ | `analyze_repo` | ✓ Implemented | 7 |
17
+ | `propose_auth_rewire` | ✓ Implemented (FastAPI kit; others as concierge surfaces them) | 4 |
18
+ | `apply_auth_rewire` | ✓ Implemented | 6 |
19
+ | `validate_compliance` | ✓ Implemented | 7 |
20
+ | `generate_manifest` | ✓ Implemented | 8 |
21
+ | `boot_test_local` | ✓ Implemented (integration; requires local docker) | — |
22
+ | `package_image` | ✓ Implemented (integration; requires local docker) | — |
23
+ | `push_image` | ✓ Implemented (integration; requires local docker + saastore registry token) | — |
24
+
25
+ Unit tests: 32/32. Integration paths (boot_test_local, package_image,
26
+ push_image) are covered by the saastore monorepo's
27
+ `scripts/smoke_hosted_auth.sh` since they shell out to docker.
28
+
29
+ ## Install (during PoC)
30
+
31
+ ```bash
32
+ cd tools/saastore-port
33
+ npm install
34
+ npm run build
35
+ ```
36
+
37
+ Then point your agent at `tools/saastore-port/dist/server.js` as a stdio MCP server.
38
+
39
+ Once we ship to npm:
40
+
41
+ ```bash
42
+ npx saastore-port
43
+ ```
44
+
45
+ ## Tools
46
+
47
+ ### `analyze_repo`
48
+
49
+ Scans a repository (defaults to CWD) and detects:
50
+
51
+ - Detected languages (javascript, typescript, python, ruby, go, rust)
52
+ - Frontend framework (Next.js, Remix, Nuxt, SvelteKit, React, Vue)
53
+ - Backend framework (Express, Fastify, Hono, Koa; FastAPI, Django, Flask, Quart, Starlette)
54
+ - Auth library (NextAuth, Auth.js, Supabase Auth, Passport, Clerk, Auth0, Lucia, Firebase, Django auth, Flask-Login, Authlib, DIY JWT)
55
+ - Database (postgres, mongodb, sqlite, mysql, redis)
56
+ - Payment processors (stripe, paddle, lemonsqueezy, braintree) — **flagged as must-remove**
57
+ - External APIs called (openai, anthropic, google-genai, cohere, replicate, twilio, sendgrid, resend, aws, sentry)
58
+ - Warnings (no manifest found, invalid JSON, payment processor present)
59
+
60
+ Pure file analysis — reads `package.json` / `pyproject.toml` / `requirements.txt` / `Gemfile` / `go.mod` / `Cargo.toml`.
61
+
62
+ ### `generate_manifest`
63
+
64
+ Takes the output of `analyze_repo` plus a few seller-supplied fields and
65
+ returns a `saastore.yaml` manifest the seller commits.
66
+
67
+ Inferences from analysis:
68
+ - `app.framework`: prefers detected frontend framework, falls back to backend.
69
+ - `app.port`: 3000 for next.js / remix / nuxt; 8000 for fastapi / django / flask; 8080 otherwise.
70
+ - `auth.adapter`: derived from detected auth library (`nextauth` → `saastore-nextauth`, etc.)
71
+ - `database.postgres`: true when DB is detected as postgres
72
+ - `external_apis`: one entry per detected API (sentry excluded), uppercased to `*_API_KEY` env vars, default $5 cap
73
+
74
+ Anything can be overridden via the `input` object (see the source for the full type).
75
+
76
+ ## Development
77
+
78
+ ```bash
79
+ npm test # runs node:test with tsx
80
+ npm run build # tsc -> dist/
81
+ npm run dev # tsc --watch
82
+ ```
83
+
84
+ ## License
85
+
86
+ MIT
@@ -0,0 +1,203 @@
1
+ /**
2
+ * analyze_repo — scan a seller's repository and detect:
3
+ * - frontend / backend frameworks (Next.js, Express, FastAPI, Django, etc.)
4
+ * - auth library in use (NextAuth, Passport, Supabase Auth, Devise, etc.)
5
+ * - database type (Postgres? Mongo? SQLite?)
6
+ * - external API dependencies the app calls into
7
+ * - presence of payment processors (Stripe SDK, etc.) — flagged as
8
+ * "must remove" per spec section 6.1
9
+ *
10
+ * Pure file analysis. Reads package.json / pyproject.toml / requirements.txt /
11
+ * Gemfile / go.mod, and greps source for known library imports. Returns
12
+ * structured findings; the seller's agent decides what to do with them.
13
+ */
14
+ import { readFile } from "node:fs/promises";
15
+ import { existsSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ // ----- Detection rules -----------------------------------------------------
18
+ // (library substring on a line that looks like an import/require/from) -> tag
19
+ const JS_FRAMEWORK_RULES = [
20
+ [/(^|[^a-z])next($|[^a-z])/i, "next.js"],
21
+ [/(^|[^a-z])remix($|[^a-z])/i, "remix"],
22
+ [/(^|[^a-z])nuxt($|[^a-z])/i, "nuxt"],
23
+ [/(^|[^a-z])sveltekit($|[^a-z])/i, "sveltekit"],
24
+ [/(^|[^a-z])react($|[^a-z])/i, "react"],
25
+ [/(^|[^a-z])vue($|[^a-z])/i, "vue"],
26
+ ];
27
+ const JS_BACKEND_RULES = [
28
+ [/(^|[^a-z])express($|[^a-z])/i, "express"],
29
+ [/(^|[^a-z])fastify($|[^a-z])/i, "fastify"],
30
+ [/(^|[^a-z])hono($|[^a-z])/i, "hono"],
31
+ [/(^|[^a-z])koa($|[^a-z])/i, "koa"],
32
+ ];
33
+ const JS_AUTH_RULES = [
34
+ [/next-auth/i, "nextauth"],
35
+ [/@auth\/[a-z-]+/i, "auth.js"],
36
+ [/@supabase\/auth/i, "supabase-auth"],
37
+ [/@supabase\/supabase-js/i, "supabase-auth"],
38
+ [/passport/i, "passport"],
39
+ [/@clerk\/[a-z-]+/i, "clerk"],
40
+ [/@auth0\/[a-z-]+/i, "auth0"],
41
+ [/lucia/i, "lucia"],
42
+ [/firebase\/auth/i, "firebase-auth"],
43
+ ];
44
+ const PY_FRAMEWORK_RULES = [
45
+ [/fastapi/i, "fastapi"],
46
+ [/^django|[^a-z]django[^a-z]/i, "django"],
47
+ [/flask/i, "flask"],
48
+ [/quart/i, "quart"],
49
+ [/starlette/i, "starlette"],
50
+ ];
51
+ const PY_AUTH_RULES = [
52
+ [/django\.contrib\.auth/i, "django-auth"],
53
+ [/flask-login/i, "flask-login"],
54
+ [/authlib/i, "authlib"],
55
+ [/python-jose|pyjwt/i, "diy-jwt"],
56
+ ];
57
+ const DB_RULES = [
58
+ [/postgres|pg\b|psycopg|asyncpg|prisma|drizzle/i, "postgres"],
59
+ [/mongo/i, "mongodb"],
60
+ [/sqlite/i, "sqlite"],
61
+ [/mysql|mariadb/i, "mysql"],
62
+ [/redis/i, "redis"],
63
+ ];
64
+ const PAYMENT_RULES = [
65
+ [/stripe/i, "stripe"],
66
+ [/paddle/i, "paddle"],
67
+ [/lemonsqueezy/i, "lemonsqueezy"],
68
+ [/braintree/i, "braintree"],
69
+ ];
70
+ const EXTERNAL_API_RULES = [
71
+ [/openai/i, "openai"],
72
+ [/anthropic/i, "anthropic"],
73
+ [/google-genai|@google\/genai/i, "google-genai"],
74
+ [/cohere/i, "cohere"],
75
+ [/replicate/i, "replicate"],
76
+ [/twilio/i, "twilio"],
77
+ [/sendgrid|@sendgrid\//i, "sendgrid"],
78
+ [/resend/i, "resend"],
79
+ [/aws-sdk/i, "aws"],
80
+ [/sentry/i, "sentry"],
81
+ ];
82
+ // ----- Helpers -------------------------------------------------------------
83
+ function applyRules(text, rules, bag) {
84
+ for (const [pat, tag] of rules) {
85
+ if (pat.test(text))
86
+ bag.add(tag);
87
+ }
88
+ }
89
+ function pickFirstOrNull(set) {
90
+ return set.size > 0 ? [...set][0] : null;
91
+ }
92
+ async function readIfExists(path) {
93
+ if (!existsSync(path))
94
+ return null;
95
+ try {
96
+ return await readFile(path, "utf8");
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ // ----- Main entry ----------------------------------------------------------
103
+ /**
104
+ * Walk `root` (one level deep is enough for package manifests; we also peek
105
+ * at first-level source files like next.config.* and a couple of source
106
+ * roots) and return structured findings.
107
+ */
108
+ export async function analyzeRepo(root) {
109
+ const warnings = [];
110
+ const languages = new Set();
111
+ const frameworks = new Set();
112
+ const backend = new Set();
113
+ const auth = new Set();
114
+ const db = new Set();
115
+ const payments = new Set();
116
+ const externalApis = new Set();
117
+ const manifestsSeen = [];
118
+ // --- JS/TS: package.json -------------------------------------------------
119
+ const pkgJson = await readIfExists(join(root, "package.json"));
120
+ if (pkgJson !== null) {
121
+ manifestsSeen.push("package.json");
122
+ languages.add("javascript");
123
+ let parsed = null;
124
+ try {
125
+ parsed = JSON.parse(pkgJson);
126
+ }
127
+ catch {
128
+ warnings.push("package.json is not valid JSON; skipping");
129
+ }
130
+ if (parsed) {
131
+ const deps = {
132
+ ...parsed.dependencies,
133
+ ...parsed.devDependencies,
134
+ };
135
+ const depString = Object.keys(deps).join("\n");
136
+ applyRules(depString, JS_FRAMEWORK_RULES, frameworks);
137
+ applyRules(depString, JS_BACKEND_RULES, backend);
138
+ applyRules(depString, JS_AUTH_RULES, auth);
139
+ applyRules(depString, DB_RULES, db);
140
+ applyRules(depString, PAYMENT_RULES, payments);
141
+ applyRules(depString, EXTERNAL_API_RULES, externalApis);
142
+ if (Object.keys(deps).some((d) => d.includes("typescript"))) {
143
+ languages.add("typescript");
144
+ }
145
+ }
146
+ }
147
+ // --- Python: pyproject.toml + requirements.txt --------------------------
148
+ const pyProject = await readIfExists(join(root, "pyproject.toml"));
149
+ if (pyProject !== null) {
150
+ manifestsSeen.push("pyproject.toml");
151
+ languages.add("python");
152
+ applyRules(pyProject, PY_FRAMEWORK_RULES, backend);
153
+ applyRules(pyProject, PY_AUTH_RULES, auth);
154
+ applyRules(pyProject, DB_RULES, db);
155
+ applyRules(pyProject, PAYMENT_RULES, payments);
156
+ applyRules(pyProject, EXTERNAL_API_RULES, externalApis);
157
+ }
158
+ const reqTxt = await readIfExists(join(root, "requirements.txt"));
159
+ if (reqTxt !== null) {
160
+ manifestsSeen.push("requirements.txt");
161
+ languages.add("python");
162
+ applyRules(reqTxt, PY_FRAMEWORK_RULES, backend);
163
+ applyRules(reqTxt, PY_AUTH_RULES, auth);
164
+ applyRules(reqTxt, DB_RULES, db);
165
+ applyRules(reqTxt, PAYMENT_RULES, payments);
166
+ applyRules(reqTxt, EXTERNAL_API_RULES, externalApis);
167
+ }
168
+ // --- Other ecosystems (presence only; PoC doesn't dig deeper) -----------
169
+ if (existsSync(join(root, "Gemfile"))) {
170
+ manifestsSeen.push("Gemfile");
171
+ languages.add("ruby");
172
+ }
173
+ if (existsSync(join(root, "go.mod"))) {
174
+ manifestsSeen.push("go.mod");
175
+ languages.add("go");
176
+ }
177
+ if (existsSync(join(root, "Cargo.toml"))) {
178
+ manifestsSeen.push("Cargo.toml");
179
+ languages.add("rust");
180
+ }
181
+ // --- Sanity warnings ----------------------------------------------------
182
+ if (manifestsSeen.length === 0) {
183
+ warnings.push("no recognised package manifest found; is this a repo root?");
184
+ }
185
+ if (payments.size > 0) {
186
+ warnings.push(`payment processor(s) detected (${[...payments].join(", ")}); per spec section 6.1 the seller's app must NOT process payments — saastore is merchant-of-record. Remove before packaging.`);
187
+ }
188
+ return {
189
+ detected_languages: [...languages].sort(),
190
+ framework: pickFirstOrNull(frameworks),
191
+ backend_framework: pickFirstOrNull(backend),
192
+ auth_library: pickFirstOrNull(auth),
193
+ database: pickFirstOrNull(db),
194
+ external_apis: [...externalApis].sort(),
195
+ payment_processors: [...payments].sort(),
196
+ package_manifests: manifestsSeen,
197
+ warnings,
198
+ };
199
+ }
200
+ // Re-export read helpers so the test file (and other tools) can stub them
201
+ // without re-implementing.
202
+ export const __test = { readIfExists };
203
+ //# sourceMappingURL=analyze_repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze_repo.js","sourceRoot":"","sources":["../src/analyze_repo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAiB,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAgBhC,8EAA8E;AAE9E,8EAA8E;AAC9E,MAAM,kBAAkB,GAA4B;IAClD,CAAC,2BAA2B,EAAE,SAAS,CAAC;IACxC,CAAC,4BAA4B,EAAE,OAAO,CAAC;IACvC,CAAC,2BAA2B,EAAE,MAAM,CAAC;IACrC,CAAC,gCAAgC,EAAE,WAAW,CAAC;IAC/C,CAAC,4BAA4B,EAAE,OAAO,CAAC;IACvC,CAAC,0BAA0B,EAAE,KAAK,CAAC;CACpC,CAAA;AACD,MAAM,gBAAgB,GAA4B;IAChD,CAAC,8BAA8B,EAAE,SAAS,CAAC;IAC3C,CAAC,8BAA8B,EAAE,SAAS,CAAC;IAC3C,CAAC,2BAA2B,EAAE,MAAM,CAAC;IACrC,CAAC,0BAA0B,EAAE,KAAK,CAAC;CACpC,CAAA;AACD,MAAM,aAAa,GAA4B;IAC7C,CAAC,YAAY,EAAE,UAAU,CAAC;IAC1B,CAAC,iBAAiB,EAAE,SAAS,CAAC;IAC9B,CAAC,kBAAkB,EAAE,eAAe,CAAC;IACrC,CAAC,yBAAyB,EAAE,eAAe,CAAC;IAC5C,CAAC,WAAW,EAAE,UAAU,CAAC;IACzB,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAC7B,CAAC,QAAQ,EAAE,OAAO,CAAC;IACnB,CAAC,iBAAiB,EAAE,eAAe,CAAC;CACrC,CAAA;AAED,MAAM,kBAAkB,GAA4B;IAClD,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,6BAA6B,EAAE,QAAQ,CAAC;IACzC,CAAC,QAAQ,EAAE,OAAO,CAAC;IACnB,CAAC,QAAQ,EAAE,OAAO,CAAC;IACnB,CAAC,YAAY,EAAE,WAAW,CAAC;CAC5B,CAAA;AACD,MAAM,aAAa,GAA4B;IAC7C,CAAC,wBAAwB,EAAE,aAAa,CAAC;IACzC,CAAC,cAAc,EAAE,aAAa,CAAC;IAC/B,CAAC,UAAU,EAAE,SAAS,CAAC;IACvB,CAAC,oBAAoB,EAAE,SAAS,CAAC;CAClC,CAAA;AAED,MAAM,QAAQ,GAA4B;IACxC,CAAC,+CAA+C,EAAE,UAAU,CAAC;IAC7D,CAAC,QAAQ,EAAE,SAAS,CAAC;IACrB,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,gBAAgB,EAAE,OAAO,CAAC;IAC3B,CAAC,QAAQ,EAAE,OAAO,CAAC;CACpB,CAAA;AACD,MAAM,aAAa,GAA4B;IAC7C,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,eAAe,EAAE,cAAc,CAAC;IACjC,CAAC,YAAY,EAAE,WAAW,CAAC;CAC5B,CAAA;AACD,MAAM,kBAAkB,GAA4B;IAClD,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,YAAY,EAAE,WAAW,CAAC;IAC3B,CAAC,8BAA8B,EAAE,cAAc,CAAC;IAChD,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,YAAY,EAAE,WAAW,CAAC;IAC3B,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,uBAAuB,EAAE,UAAU,CAAC;IACrC,CAAC,SAAS,EAAE,QAAQ,CAAC;IACrB,CAAC,UAAU,EAAE,KAAK,CAAC;IACnB,CAAC,SAAS,EAAE,QAAQ,CAAC;CACtB,CAAA;AAED,8EAA8E;AAE9E,SAAS,UAAU,CACjB,IAAY,EACZ,KAA8B,EAC9B,GAAgB;IAEhB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAClC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,GAAgB;IACvC,OAAO,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC1C,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAClC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IACnC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,EAAE,GAAG,IAAI,GAAG,EAAU,CAAA;IAC5B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAA;IACtC,MAAM,aAAa,GAAa,EAAE,CAAA;IAElC,4EAA4E;IAC5E,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAA;IAC9D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAClC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC3B,IAAI,MAAM,GAAmC,IAAI,CAAA;QACjD,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAA;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAG;gBACX,GAAI,MAAM,CAAC,YAAmD;gBAC9D,GAAI,MAAM,CAAC,eAAsD;aAClE,CAAA;YACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC9C,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAA;YACrD,UAAU,CAAC,SAAS,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAA;YAChD,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,CAAC,CAAA;YAC1C,UAAU,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;YACnC,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAA;YAC9C,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAA;YACvD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;gBAC5D,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAClE,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QACpC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACvB,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAA;QAClD,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,CAAC,CAAA;QAC1C,UAAU,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;QACnC,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAA;QAC9C,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAA;IACzD,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAA;IACjE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,aAAa,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACtC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACvB,UAAU,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAA;QAC/C,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,CAAC,CAAA;QACvC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;QAChC,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAA;QAC3C,UAAU,CAAC,MAAM,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAA;IACtD,CAAC;IAED,2EAA2E;IAC3E,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QACtC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QACrC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC5B,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QACzC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAChC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;IAED,2EAA2E;IAC3E,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,QAAQ,CAAC,IAAI,CACX,4DAA4D,CAC7D,CAAA;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CACX,kCAAkC,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,+HAA+H,CAC1L,CAAA;IACH,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,EAAE;QACzC,SAAS,EAAE,eAAe,CAAC,UAAU,CAAC;QACtC,iBAAiB,EAAE,eAAe,CAAC,OAAO,CAAC;QAC3C,YAAY,EAAE,eAAe,CAAC,IAAI,CAAC;QACnC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;QAC7B,aAAa,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE;QACvC,kBAAkB,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE;QACxC,iBAAiB,EAAE,aAAa;QAChC,QAAQ;KACT,CAAA;AACH,CAAC;AAED,0EAA0E;AAC1E,2BAA2B;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * apply_auth_rewire — write the create-intent files from a RewireProposal
3
+ * to the seller's working tree. Modify/delete intents are returned as
4
+ * "next steps" hints; the seller's agent applies them with its own AST/
5
+ * full-source context (we deliberately don't try to do source rewriting
6
+ * blind).
7
+ *
8
+ * Idempotent: refuses to overwrite an existing file unless force=true.
9
+ * Returns a structured result the agent uses to present a summary.
10
+ */
11
+ import { existsSync } from "node:fs";
12
+ import { mkdir, writeFile } from "node:fs/promises";
13
+ import { dirname, join } from "node:path";
14
+ // ----- Main entry ----------------------------------------------------------
15
+ export async function applyAuthRewire(proposal, opts = {}) {
16
+ const root = opts.root ?? process.cwd();
17
+ const force = opts.force ?? false;
18
+ const dryRun = opts.dry_run ?? false;
19
+ const applied = [];
20
+ const nextSteps = [];
21
+ const warnings = [...proposal.warnings];
22
+ for (const change of proposal.changes) {
23
+ if (change.intent !== "create") {
24
+ // modify + delete need source-aware tooling — pass them back to the agent
25
+ nextSteps.push(change);
26
+ continue;
27
+ }
28
+ if (!change.contents) {
29
+ warnings.push(`change for ${change.path}: intent=create but no contents — skipping`);
30
+ continue;
31
+ }
32
+ const absPath = join(root, ...change.path.split("/"));
33
+ if (existsSync(absPath) && !force) {
34
+ applied.push({
35
+ path: change.path,
36
+ status: "skipped_exists",
37
+ reason: `file exists; re-run with force=true to overwrite`,
38
+ });
39
+ continue;
40
+ }
41
+ if (dryRun) {
42
+ applied.push({
43
+ path: change.path,
44
+ status: "deferred",
45
+ reason: "dry_run=true; nothing written",
46
+ });
47
+ continue;
48
+ }
49
+ await mkdir(dirname(absPath), { recursive: true });
50
+ await writeFile(absPath, change.contents, "utf8");
51
+ applied.push({
52
+ path: change.path,
53
+ status: "written",
54
+ reason: change.reason,
55
+ });
56
+ }
57
+ return {
58
+ framework: proposal.framework,
59
+ applied,
60
+ next_steps: nextSteps,
61
+ warnings,
62
+ };
63
+ }
64
+ //# sourceMappingURL=apply_auth_rewire.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply_auth_rewire.js","sourceRoot":"","sources":["../src/apply_auth_rewire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AA4BzC,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAwB,EACxB,OAAqB,EAAE;IAEvB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAA;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;IAEpC,MAAM,OAAO,GAAkB,EAAE,CAAA;IACjC,MAAM,SAAS,GAAqB,EAAE,CAAA;IACtC,MAAM,QAAQ,GAAa,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAEjD,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,0EAA0E;YAC1E,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACtB,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CACX,cAAc,MAAM,CAAC,IAAI,4CAA4C,CACtE,CAAA;YACD,SAAQ;QACV,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;QACrD,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,gBAAgB;gBACxB,MAAM,EAAE,kDAAkD;aAC3D,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,UAAU;gBAClB,MAAM,EAAE,+BAA+B;aACxC,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QACD,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QACjD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,OAAO;QACP,UAAU,EAAE,SAAS;QACrB,QAAQ;KACT,CAAA;AACH,CAAC"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * boot_test_local — replicate scripts/smoke_hosted_auth.sh as an MCP tool the
3
+ * seller's agent can drive locally. Builds the seller's Docker image, runs
4
+ * it on a random local port with a known SAASTORE_HMAC_SECRET, then probes:
5
+ *
6
+ * - GET /health -> expect 200
7
+ * - GET /whoami with valid signed headers -> expect 200
8
+ * - GET /whoami with bad signature -> expect 401
9
+ * - GET /whoami with stale timestamp -> expect 401
10
+ *
11
+ * Returns a structured per-step result. The container is always destroyed
12
+ * in finally.
13
+ */
14
+ import { spawn } from "node:child_process";
15
+ import { createHmac } from "node:crypto";
16
+ // ----- Helpers -------------------------------------------------------------
17
+ function run(cmd, args, opts = {}) {
18
+ return new Promise((resolve) => {
19
+ const proc = spawn(cmd, args, { cwd: opts.cwd, shell: false });
20
+ let stdout = "";
21
+ let stderr = "";
22
+ proc.stdout?.on("data", (d) => (stdout += d.toString()));
23
+ proc.stderr?.on("data", (d) => (stderr += d.toString()));
24
+ let timer;
25
+ if (opts.timeout_ms) {
26
+ timer = setTimeout(() => proc.kill("SIGKILL"), opts.timeout_ms);
27
+ }
28
+ proc.on("close", (code) => {
29
+ if (timer)
30
+ clearTimeout(timer);
31
+ resolve({ code: code ?? -1, stdout, stderr });
32
+ });
33
+ });
34
+ }
35
+ function sign(secret, userId, email, plan, ts) {
36
+ const msg = `${userId}|${email}|${plan}|${ts}`;
37
+ return createHmac("sha256", secret).update(msg).digest("hex");
38
+ }
39
+ async function httpStatus(url, headers = {}) {
40
+ try {
41
+ const resp = await fetch(url, { headers });
42
+ return resp.status;
43
+ }
44
+ catch {
45
+ return -1;
46
+ }
47
+ }
48
+ async function httpText(url, headers = {}) {
49
+ try {
50
+ const resp = await fetch(url, { headers });
51
+ const text = await resp.text();
52
+ return { status: resp.status, text };
53
+ }
54
+ catch (e) {
55
+ return { status: -1, text: String(e) };
56
+ }
57
+ }
58
+ async function waitForHealth(port, timeoutS) {
59
+ const deadline = Date.now() + timeoutS * 1000;
60
+ while (Date.now() < deadline) {
61
+ const status = await httpStatus(`http://localhost:${port}/health`);
62
+ if (status === 200)
63
+ return true;
64
+ await new Promise((r) => setTimeout(r, 500));
65
+ }
66
+ return false;
67
+ }
68
+ // ----- Main entry ----------------------------------------------------------
69
+ export async function bootTestLocal(opts = {}) {
70
+ const context = opts.context ?? process.cwd();
71
+ const dockerfile = opts.dockerfile ?? "Dockerfile";
72
+ const hostPort = opts.port ?? 8765;
73
+ const containerPort = opts.container_port ?? 8000;
74
+ const secret = opts.secret ?? "test-secret-32bytes-or-more-long-enough-for-real-use";
75
+ const timeoutS = opts.startup_timeout_s ?? 30;
76
+ const dockerBin = opts.docker_bin ?? "docker";
77
+ const userId = "9a3f12cd-1111-2222-3333-444455556666";
78
+ const email = "buyer@example.com";
79
+ const plan = "poc";
80
+ const tag = `saastore-bootlocal:${Date.now().toString(36)}`;
81
+ const steps = [];
82
+ let cid = null;
83
+ try {
84
+ // 1. Build the image
85
+ const build = await run(dockerBin, ["build", "-f", dockerfile, "-t", tag, "."], { cwd: context, timeout_ms: 5 * 60_000 });
86
+ if (build.code !== 0) {
87
+ steps.push({
88
+ name: "docker_build",
89
+ ok: false,
90
+ detail: `exit=${build.code}\n${build.stderr.slice(-500)}`,
91
+ });
92
+ return { ok: false, image_tag: tag, port: hostPort, steps };
93
+ }
94
+ steps.push({ name: "docker_build", ok: true, detail: `built ${tag}` });
95
+ // 2. Run the container detached
96
+ const runRes = await run(dockerBin, [
97
+ "run",
98
+ "-d",
99
+ "--rm",
100
+ "-p",
101
+ `${hostPort}:${containerPort}`,
102
+ "-e",
103
+ `SAASTORE_HMAC_SECRET=${secret}`,
104
+ tag,
105
+ ], { timeout_ms: 30_000 });
106
+ if (runRes.code !== 0) {
107
+ steps.push({
108
+ name: "docker_run",
109
+ ok: false,
110
+ detail: `exit=${runRes.code}\n${runRes.stderr.slice(-500)}`,
111
+ });
112
+ return { ok: false, image_tag: tag, port: hostPort, steps };
113
+ }
114
+ cid = runRes.stdout.trim();
115
+ steps.push({ name: "docker_run", ok: true, detail: `cid=${cid.slice(0, 12)}` });
116
+ // 3. Wait for /health
117
+ const healthy = await waitForHealth(hostPort, timeoutS);
118
+ if (!healthy) {
119
+ steps.push({
120
+ name: "health_200",
121
+ ok: false,
122
+ detail: `/health did not return 200 within ${timeoutS}s`,
123
+ });
124
+ return { ok: false, image_tag: tag, port: hostPort, steps };
125
+ }
126
+ steps.push({ name: "health_200", ok: true, detail: "/health returned 200" });
127
+ // 4. /whoami with valid signed headers -> 200
128
+ const ts = Math.floor(Date.now() / 1000);
129
+ const sig = sign(secret, userId, email, plan, ts);
130
+ const valid = await httpText(`http://localhost:${hostPort}/whoami`, {
131
+ "X-Saastore-Buyer-Id": userId,
132
+ "X-Saastore-User-Email": email,
133
+ "X-Saastore-Plan": plan,
134
+ "X-Saastore-Timestamp": String(ts),
135
+ "X-Saastore-Signature": sig,
136
+ });
137
+ if (valid.status !== 200) {
138
+ steps.push({
139
+ name: "whoami_signed_200",
140
+ ok: false,
141
+ detail: `expected 200, got ${valid.status}; body: ${valid.text.slice(0, 200)}`,
142
+ });
143
+ return { ok: false, image_tag: tag, port: hostPort, steps };
144
+ }
145
+ steps.push({
146
+ name: "whoami_signed_200",
147
+ ok: true,
148
+ detail: `/whoami returned 200`,
149
+ });
150
+ // 5. /whoami with bad signature -> 401
151
+ const badStatus = await httpStatus(`http://localhost:${hostPort}/whoami`, {
152
+ "X-Saastore-Buyer-Id": userId,
153
+ "X-Saastore-User-Email": email,
154
+ "X-Saastore-Plan": plan,
155
+ "X-Saastore-Timestamp": String(ts),
156
+ "X-Saastore-Signature": "0".repeat(64),
157
+ });
158
+ if (badStatus !== 401) {
159
+ steps.push({
160
+ name: "whoami_badsig_401",
161
+ ok: false,
162
+ detail: `expected 401, got ${badStatus}`,
163
+ });
164
+ return { ok: false, image_tag: tag, port: hostPort, steps };
165
+ }
166
+ steps.push({
167
+ name: "whoami_badsig_401",
168
+ ok: true,
169
+ detail: "bad signature correctly rejected",
170
+ });
171
+ // 6. /whoami with stale timestamp -> 401
172
+ const staleTs = ts - 10 * 60;
173
+ const staleSig = sign(secret, userId, email, plan, staleTs);
174
+ const staleStatus = await httpStatus(`http://localhost:${hostPort}/whoami`, {
175
+ "X-Saastore-Buyer-Id": userId,
176
+ "X-Saastore-User-Email": email,
177
+ "X-Saastore-Plan": plan,
178
+ "X-Saastore-Timestamp": String(staleTs),
179
+ "X-Saastore-Signature": staleSig,
180
+ });
181
+ if (staleStatus !== 401) {
182
+ steps.push({
183
+ name: "whoami_stale_401",
184
+ ok: false,
185
+ detail: `expected 401, got ${staleStatus}`,
186
+ });
187
+ return { ok: false, image_tag: tag, port: hostPort, steps };
188
+ }
189
+ steps.push({
190
+ name: "whoami_stale_401",
191
+ ok: true,
192
+ detail: "stale timestamp correctly rejected",
193
+ });
194
+ return { ok: true, image_tag: tag, port: hostPort, steps };
195
+ }
196
+ finally {
197
+ if (cid) {
198
+ await run(dockerBin, ["stop", cid], { timeout_ms: 10_000 }).catch(() => { });
199
+ }
200
+ }
201
+ }
202
+ //# sourceMappingURL=boot_test_local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot_test_local.js","sourceRoot":"","sources":["../src/boot_test_local.ts"],"names":[],"mappings":"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"}