From 3ef53864bad245a86453a13e901f4159f1e114c8 Mon Sep 17 00:00:00 2001 From: "Ralph Sto. Domingo" Date: Thu, 24 Sep 2026 12:04:00 +0800 Subject: [PATCH] fix(dbt-tools): move to dbt-integration 0.3.13 so the dbt adapter starts under Bun `dbt-tools` resolved `@altimateai/dbt-integration` 0.2.14, which spawns its Python child through `python-bridge`. Under Bun that module fails to load (`bluebird.promisifyAll(child_process)` throws on `ChildProcess.prototype.stdin`), and past that, Bun's IPC to a non-JS child closes after the first message. So the dbt-first path of `sql_execute` never ran; the adapter silently fell back. 0.3.x vendors the bridge and talks newline JSON over a plain fd-3 pipe, with no `python-bridge` or `bluebird` in the tree. - `adapter.ts`: the 0.3.x constructors take `UnitTestParser` and `SemanticModelParser`; the Fusion integration no longer takes the cloud-variant detector (the Cloud integration still does). - `copy-python.ts`: the vendored bridge resolves its script from the bundle's own location at runtime, so the `python-bridge` `__dirname` patch is gone; the build now fails if a build-time path is baked in. `build-adversarial.test.ts` tested only that patch and is removed; `build-integrity.test.ts` and the release smoke check assert the new invariant. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0172qrhMa5TQgETASi5hxMqD --- .github/workflows/release.yml | 6 +- bun.lock | 82 +-- packages/dbt-tools/package.json | 2 +- packages/dbt-tools/script/copy-python.ts | 29 +- packages/dbt-tools/src/adapter.ts | 5 +- .../dbt-tools/test/build-adversarial.test.ts | 484 ------------------ .../dbt-tools/test/build-integrity.test.ts | 12 +- packages/opencode/script/publish.ts | 6 +- 8 files changed, 50 insertions(+), 576 deletions(-) delete mode 100644 packages/dbt-tools/test/build-adversarial.test.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24fa9a1319..3c8ae0c86b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -286,9 +286,9 @@ jobs: echo "::error::dbt-tools bundle contains hardcoded absolute path in __dirname" exit 1 fi - # Verify __dirname was patched to runtime resolution - if ! grep -q 'import.meta.dirname' packages/dbt-tools/dist/index.js; then - echo "::error::dbt-tools bundle missing import.meta.dirname patch" + # Verify the bridge script resolves relative to the bundle at runtime + if ! grep -q 'fileURLToPath(import.meta.url)' packages/dbt-tools/dist/index.js; then + echo "::error::dbt-tools bundle does not resolve node_python_bridge.py at runtime" exit 1 fi echo "dbt-tools smoke test passed" diff --git a/bun.lock b/bun.lock index 0495f7f8cd..8c5a0bc1ce 100644 --- a/bun.lock +++ b/bun.lock @@ -150,7 +150,7 @@ "altimate-dbt": "./bin/altimate-dbt", }, "dependencies": { - "@altimateai/dbt-integration": "^0.2.2", + "@altimateai/dbt-integration": "^0.3.13", }, "devDependencies": { "@tsconfig/bun": "catalog:", @@ -654,7 +654,7 @@ "@altimateai/altimate-core-win32-x64-msvc": ["@altimateai/altimate-core-win32-x64-msvc@0.7.0", "", { "os": "win32", "cpu": "x64" }, "sha512-GrykrvnilY1yZCgusNxVTvYr5ENkD1vpgjGib2qX/yvJVs0Nb59/JsSLzvA9XqAt2FVf7OcZ5ttH11OkxuFivg=="], - "@altimateai/dbt-integration": ["@altimateai/dbt-integration@0.2.14", "", { "dependencies": { "@altimateai/altimate-core": "0.1.6", "node-abort-controller": "^3.1.1", "node-fetch": "^3.3.2", "python-bridge": "^1.1.0", "semver": "^7.6.3", "yaml": "^2.5.0" }, "peerDependencies": { "patch-package": "^8.0.0" } }, "sha512-44hFBx3gXss2RUlRZE9cIpAocffB3miAzpjvmma1EED0jiOhyrgmzGsw3RXEZqs73OuLYpDehixvRUt1vTfcfQ=="], + "@altimateai/dbt-integration": ["@altimateai/dbt-integration@0.3.13", "", { "dependencies": { "@altimateai/altimate-core": "0.5.0", "node-abort-controller": "^3.1.1", "node-fetch": "^3.3.2", "semver": "^7.6.3", "yaml": "^2.5.0" } }, "sha512-9X7zEQnuEM5QqPOfBk8qTeb4IhsZbEUCaxTsfipLuhrvHQcfEvuUh07scw6VyZg6Dx/OKbpiV0DDpAMcyFkwWg=="], "@altimateai/dbt-tools": ["@altimateai/dbt-tools@workspace:packages/dbt-tools"], @@ -1518,8 +1518,6 @@ "@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="], - "@yarnpkg/lockfile": ["@yarnpkg/lockfile@1.1.0", "", {}, "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="], - "@zip.js/zip.js": ["@zip.js/zip.js@2.7.62", "", {}, "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA=="], "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], @@ -1634,8 +1632,6 @@ "bl": ["bl@6.1.6", "", { "dependencies": { "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" } }, "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg=="], - "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], - "bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], @@ -1678,8 +1674,6 @@ "cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="], - "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], @@ -1720,9 +1714,9 @@ "color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="], - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], "color-string": ["color-string@2.1.4", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg=="], @@ -1788,8 +1782,6 @@ "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], @@ -1964,8 +1956,6 @@ "find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], - "find-yarn-workspace-root": ["find-yarn-workspace-root@2.0.0", "", { "dependencies": { "micromatch": "^4.0.2" } }, "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ=="], - "flatbuffers": ["flatbuffers@23.5.26", "", {}, "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ=="], "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], @@ -1982,8 +1972,6 @@ "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -2042,8 +2030,6 @@ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], @@ -2144,7 +2130,7 @@ "is64bit": ["is64bit@2.0.0", "", { "dependencies": { "system-architecture": "^0.1.0" } }, "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw=="], - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], @@ -2182,8 +2168,6 @@ "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], - "json-stable-stringify": ["json-stable-stringify@1.3.0", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "isarray": "^2.0.5", "jsonify": "^0.0.1", "object-keys": "^1.1.1" } }, "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg=="], - "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], "json-with-bigint": ["json-with-bigint@3.5.8", "", {}, "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw=="], @@ -2192,10 +2176,6 @@ "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], - - "jsonify": ["jsonify@0.0.1", "", {}, "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg=="], - "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], "jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="], @@ -2212,8 +2192,6 @@ "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], - "klaw-sync": ["klaw-sync@6.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11" } }, "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ=="], - "kubernetes-types": ["kubernetes-types@1.30.0", "", {}, "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q=="], "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], @@ -2402,8 +2380,6 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], "oidc-token-hash": ["oidc-token-hash@5.2.0", "", {}, "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw=="], @@ -2470,8 +2446,6 @@ "partial-json": ["partial-json@0.1.7", "", {}, "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA=="], - "patch-package": ["patch-package@8.0.1", "", { "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^10.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", "semver": "^7.5.3", "slash": "^2.0.0", "tmp": "^0.2.4", "yaml": "^2.2.2" }, "bin": { "patch-package": "index.js" } }, "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw=="], - "path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], "path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], @@ -2574,8 +2548,6 @@ "pure-rand": ["pure-rand@8.4.0", "", {}, "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A=="], - "python-bridge": ["python-bridge@1.1.0", "", { "dependencies": { "bluebird": "^3.5.0" } }, "sha512-qjQ0QB8p9cn/XDeILQH0aP307hV58lrmv0Opjyub68Um7FHdF+ZXlTqyxNkKaXOFk2QSkScoPWwn7U9GGnrkeQ=="], - "q": ["q@1.5.1", "", {}, "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw=="], "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], @@ -2674,8 +2646,6 @@ "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -2700,8 +2670,6 @@ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], - "slash": ["slash@2.0.0", "", {}, "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="], - "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], "snowflake-sdk": ["snowflake-sdk@2.4.3", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-sdk/client-s3": "~3.1051.0", "@aws-sdk/client-sts": "~3.1051.0", "@aws-sdk/credential-provider-node": "~3.972.43", "@aws-sdk/ec2-metadata-service": "~3.1051.0", "@azure/identity": "^4.10.1", "@azure/storage-blob": "12.26.x", "@smithy/node-http-handler": "^4.4.9", "@smithy/protocol-http": "^5.3.8", "@smithy/signature-v4": "^5.3.8", "@techteamer/ocsp": "1.0.1", "asn1.js": "^5.0.0", "asn1.js-rfc2560": "^5.0.0", "asn1.js-rfc5280": "^3.0.0", "axios": "^1.15.1", "big-integer": "^1.6.43", "bignumber.js": "^9.1.2", "expand-tilde": "^2.0.2", "fast-xml-parser": "^5.4.1", "fastest-levenshtein": "^1.0.16", "generic-pool": "^3.8.2", "google-auth-library": "^10.1.0", "https-proxy-agent": "^7.0.2", "jsonwebtoken": "^9.0.3", "mime-types": "^2.1.29", "moment": "^2.29.4", "moment-timezone": "^0.5.15", "oauth4webapi": "^3.0.1", "open": "^7.3.1", "simple-lru-cache": "^0.0.2", "toml": "^3.0.0", "winston": "^3.1.0" } }, "sha512-R9f4CL34RcgAL/8o1iOfbfUk1Dc58eHTKFt9IqVUqnnBdiyu583m81nh7c4tTiB3/TeJGIi1BTRJONV+K5tfxQ=="], @@ -2808,8 +2776,6 @@ "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - "tmp": ["tmp@0.2.7", "", {}, "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw=="], - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toad-cache": ["toad-cache@3.7.1", "", {}, "sha512-5DXWzE4Vz7xNHsv+xQ+MGfJYyC78Aok3tEr0MNwHoRf7vZnga1mQXZ4/Nsodld4VR6Wd+VhfmqnNrsRJyYPfrQ=="], @@ -2890,8 +2856,6 @@ "universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="], - "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "unzip-stream": ["unzip-stream@0.3.4", "", { "dependencies": { "binary": "^0.3.0", "mkdirp": "^0.5.1" } }, "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw=="], @@ -3064,7 +3028,7 @@ "@ai-sdk/vercel/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], - "@altimateai/dbt-integration/@altimateai/altimate-core": ["@altimateai/altimate-core@0.1.6", "", { "optionalDependencies": { "@altimateai/altimate-core-darwin-arm64": "0.1.6", "@altimateai/altimate-core-darwin-x64": "0.1.6", "@altimateai/altimate-core-linux-arm64-gnu": "0.1.6", "@altimateai/altimate-core-linux-x64-gnu": "0.1.6", "@altimateai/altimate-core-win32-x64-msvc": "0.1.6" } }, "sha512-Kl0hjT88Q56AdGxKJyCcPElxcpZYDYmLhDHK7ZeZIn2oVaXyynExLcIHn+HktUe9USuWtba3tZA/52jJsMyrGg=="], + "@altimateai/dbt-integration/@altimateai/altimate-core": ["@altimateai/altimate-core@0.5.0", "", { "optionalDependencies": { "@altimateai/altimate-core-darwin-arm64": "0.5.0", "@altimateai/altimate-core-darwin-x64": "0.5.0", "@altimateai/altimate-core-linux-arm64-gnu": "0.5.0", "@altimateai/altimate-core-linux-x64-gnu": "0.5.0", "@altimateai/altimate-core-win32-x64-msvc": "0.5.0" } }, "sha512-HxhZ7Q+MhsfyvQjgBEZjtXRc4XBs5WVQ/p6bjOoayl65CLcJ4MnYCjmubPAaCtOX1K3IPB+F7rLnqJMtILEqRA=="], "@altimateai/dbt-integration/yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], @@ -3240,10 +3204,6 @@ "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "color/color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="], - - "color-string/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], - "command-line-usage/array-back": ["array-back@6.2.3", "", {}, "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw=="], "command-line-usage/typical": ["typical@7.3.0", "", {}, "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw=="], @@ -3342,12 +3302,6 @@ "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "patch-package/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], - - "patch-package/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], - - "patch-package/yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], - "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "proxy-agent/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], @@ -3452,15 +3406,15 @@ "@ai-sdk/vercel/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-darwin-arm64": ["@altimateai/altimate-core-darwin-arm64@0.1.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lcndcluAsWMdI0fq2xwgukxFBwoISqKeLWBMjRAhIlCU0qVO+sR/UGUj2FiKZHIWmwgHAou3V5K2fKoYMh9PdQ=="], + "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-darwin-arm64": ["@altimateai/altimate-core-darwin-arm64@0.5.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8UhgkTa/VovAoattlVZOKLnQxN8Yw77BNIzr08KSeKh+0qqJqwb46Ub0I8SbNQAeGOyrmsTr5bmUkUhmkcU8Qw=="], - "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-darwin-x64": ["@altimateai/altimate-core-darwin-x64@0.1.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-pYD0Yj/j7SKrU5BY3utPGM4ImoZcV/6yJ7cTFGQXONj3Ikmoo1FdUZR5/CgZE7CCYAa0T9pjOfxB1rLD1B1fxQ=="], + "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-darwin-x64": ["@altimateai/altimate-core-darwin-x64@0.5.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-6rXtiu32A9AgJ4fhHv78oxucRz5BjttOIF8S0tBgDDQjHtesyQV5cr84JsZPNXyQCIBHU/dWS3Hgu4NwtjHfQg=="], - "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-linux-arm64-gnu": ["@altimateai/altimate-core-linux-arm64-gnu@0.1.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-VDxrk3z30cWJfIudpiGbAz+PFpYB2OE+XSyOPFN+GI7K9NOd5RtC7e9pG50nMF55Wz5R5Yp0ywa/dL+QpUp8SA=="], + "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-linux-arm64-gnu": ["@altimateai/altimate-core-linux-arm64-gnu@0.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-ebELtWOJVGQeGT64LC5qMp+FLxOao9o2t5uFTa/eMKgDpnfkRb+nkcuQIaeXxUVcTZ4JDeEyAuC8WyrY8ZN81g=="], - "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-linux-x64-gnu": ["@altimateai/altimate-core-linux-x64-gnu@0.1.6", "", { "os": "linux", "cpu": "x64" }, "sha512-wXWYNxGhUBBaf2b6dsvuD1ZuiTLQZbKg4/fckrQELuW+BrsN1+nzna+0IZ9FTATYfF1OatpqVun9QyBkvlQn+Q=="], + "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-linux-x64-gnu": ["@altimateai/altimate-core-linux-x64-gnu@0.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-sNLNn1SQnCosbyuSj3QOm3RRmQNoq2pCrEIHPSZf+Ml2l2BFN0zxISgvxdrhx94wZo37ITFWWPar9uL6HP0yBA=="], - "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-win32-x64-msvc": ["@altimateai/altimate-core-win32-x64-msvc@0.1.6", "", { "os": "win32", "cpu": "x64" }, "sha512-6Sbneg0DLHMmo1lDVd9oDgGtqPJpDUXZvXwAbGb7eoh+vUmXMxABA43//hBbwkMVsWKClKjv1KXSKp44shrUiw=="], + "@altimateai/dbt-integration/@altimateai/altimate-core/@altimateai/altimate-core-win32-x64-msvc": ["@altimateai/altimate-core-win32-x64-msvc@0.5.0", "", { "os": "win32", "cpu": "x64" }, "sha512-9mf9lF7xDdfRr2XQ1otOTyI5nYpQ9PD1cN49KZdx/hLFO2x1EssWO43YDIoTHDN9T4FZR3CxgOiF6OkQjaz5RA=="], "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], @@ -3556,7 +3510,7 @@ "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + "chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "cross-fetch/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], @@ -3568,8 +3522,6 @@ "gauge/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "lazystream/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -3624,10 +3576,6 @@ "openid-client/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "patch-package/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], - - "patch-package/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], - "readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.1.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA=="], "rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], @@ -3646,6 +3594,8 @@ "wide-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -3682,6 +3632,8 @@ "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "cross-fetch/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "cross-fetch/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -3708,6 +3660,8 @@ "wide-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "archiver-utils/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "babel-plugin-module-resolver/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], diff --git a/packages/dbt-tools/package.json b/packages/dbt-tools/package.json index 88801d319b..ebc20646e2 100644 --- a/packages/dbt-tools/package.json +++ b/packages/dbt-tools/package.json @@ -13,7 +13,7 @@ "test:e2e": "bun test test/e2e/ --timeout 300000" }, "dependencies": { - "@altimateai/dbt-integration": "^0.2.2" + "@altimateai/dbt-integration": "^0.3.13" }, "devDependencies": { "@tsconfig/bun": "catalog:", diff --git a/packages/dbt-tools/script/copy-python.ts b/packages/dbt-tools/script/copy-python.ts index 8e93fd27f3..f200c3ae50 100644 --- a/packages/dbt-tools/script/copy-python.ts +++ b/packages/dbt-tools/script/copy-python.ts @@ -1,4 +1,4 @@ -import { cpSync, existsSync, readFileSync, writeFileSync } from "fs" +import { cpSync, existsSync, readFileSync } from "fs" import { dirname, join } from "path" const dist = join(import.meta.dir, "..", "dist") @@ -20,23 +20,16 @@ if (!existsSync(bridgePy)) { cpSync(bridgePy, join(dist, "node_python_bridge.py")) console.log(`Copied node_python_bridge.py → dist/`) -// 3. Fix the hardcoded __dirname that bun bakes at compile time. -// Replace it with a runtime resolution so the bridge script is found -// relative to the built index.js, not the CI runner's node_modules. +// 3. dbt-integration resolves node_python_bridge.py at runtime from its own +// location (`fileURLToPath(import.meta.url)`), which in this bundle is dist/, +// where step 2 put the script. Fail the build if the bundle ever carries a +// path baked in at build time instead. const indexPath = join(dist, "index.js") -let code = readFileSync(indexPath, "utf8") -const pattern = /var __dirname\s*=\s*"[^"]*python-bridge[^"]*"/ -if (pattern.test(code)) { - // import.meta.dirname is supported by Bun and Node >= 20.11.0. - // Fallback via __require handles older runtimes where import.meta.dirname is unavailable. - const replacement = `var __dirname = typeof import.meta.dirname === "string" ? import.meta.dirname : __require("path").dirname(__require("url").fileURLToPath(import.meta.url))` - code = code.replace(pattern, replacement) - writeFileSync(indexPath, code) - console.log(`Patched __dirname in dist/index.js`) -} else { - const found = code.match(/var __dirname[^;]*/)?.[0] ?? "(not found)" - console.error(`ERROR: could not find python-bridge __dirname to patch — the bundle format may have changed`) - console.error(` Pattern: ${pattern}`) - console.error(` Nearest match: ${found}`) +const code = readFileSync(indexPath, "utf8") +const baked = /var __dirname\s*=\s*"(?:[A-Za-z]:\\\\|\/)/ +if (!code.includes("fileURLToPath(import.meta.url)") || !code.includes(`"node_python_bridge.py"`) || baked.test(code)) { + console.error(`ERROR: dist/index.js does not resolve node_python_bridge.py relative to itself at runtime`) + console.error(` Has the @altimateai/dbt-integration bundle format changed?`) process.exit(1) } +console.log(`Verified dist/index.js resolves node_python_bridge.py at runtime`) diff --git a/packages/dbt-tools/src/adapter.ts b/packages/dbt-tools/src/adapter.ts index ac906b8804..5f9939da16 100644 --- a/packages/dbt-tools/src/adapter.ts +++ b/packages/dbt-tools/src/adapter.ts @@ -15,6 +15,8 @@ import { GraphParser, SourceParser, TestParser, + UnitTestParser, + SemanticModelParser, ExposureParser, FunctionParser, DocParser, @@ -181,7 +183,6 @@ export async function create(cfg: Config): Promise diag, defer, changed, - cloudVariantDetector, ) const adapter = new DBTProjectIntegrationAdapter( @@ -200,11 +201,13 @@ export async function create(cfg: Config): Promise new GraphParser(term), new SourceParser(term), new TestParser(term), + new UnitTestParser(term), new ExposureParser(term), new FunctionParser(term), new DocParser(term), term, new ModelDepthParser(term, client, config), + new SemanticModelParser(term), ) await adapter.initialize() diff --git a/packages/dbt-tools/test/build-adversarial.test.ts b/packages/dbt-tools/test/build-adversarial.test.ts deleted file mode 100644 index c5cfe343d8..0000000000 --- a/packages/dbt-tools/test/build-adversarial.test.ts +++ /dev/null @@ -1,484 +0,0 @@ -import { describe, test, expect, beforeAll } from "bun:test" -import { readFileSync, writeFileSync, mkdtempSync, cpSync, existsSync } from "fs" -import { join, resolve } from "path" -import { tmpdir } from "os" -import { $ } from "bun" - -const dist = join(import.meta.dir, "../dist") -const scriptDir = join(import.meta.dir, "../script") - -// ─── Helpers ───────────────────────────────────────────────────────── -// Simulate what copy-python.ts does against arbitrary bundle content, -// without touching the real dist/index.js. -function runPatchLogic(bundleContent: string): { patched: boolean; output: string } { - const pattern = /var __dirname\s*=\s*"[^"]*python-bridge[^"]*"/ - if (pattern.test(bundleContent)) { - const replacement = `var __dirname = typeof import.meta.dirname === "string" ? import.meta.dirname : __require("path").dirname(__require("url").fileURLToPath(import.meta.url))` - return { patched: true, output: bundleContent.replace(pattern, replacement) } - } - return { patched: false, output: bundleContent } -} - -// ─── Adversarial: Regex edge cases ────────────────────────────────── -describe("adversarial: patch regex", () => { - test("matches typical CI runner path (Linux)", () => { - const bundle = `var __dirname = "/home/runner/work/altimate-code/node_modules/.bun/python-bridge@1.1.0/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - expect(result.output).toContain("import.meta.dirname") - expect(result.output).not.toContain("/home/runner") - }) - - test("matches macOS dev path", () => { - const bundle = `var __dirname = "/Users/dev/code/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - expect(result.output).not.toContain("/Users/dev") - }) - - test("matches Windows CI path", () => { - const bundle = `var __dirname = "C:\\Users\\runneradmin\\work\\node_modules\\python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - expect(result.output).not.toContain("C:\\Users") - }) - - test("matches path with @scope in node_modules", () => { - const bundle = `var __dirname = "/opt/ci/node_modules/.bun/python-bridge@2.0.0/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("does NOT match unrelated __dirname (no python-bridge)", () => { - const bundle = `var __dirname = "/home/runner/work/some-other-module"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(false) - // The original hardcoded path is preserved — this is CORRECT behavior. - // The patch should only touch the python-bridge dirname. - }) - - test("does NOT match __dirname that's already patched", () => { - const bundle = `var __dirname = typeof import.meta.dirname === "string" ? import.meta.dirname : __require("path").dirname(__require("url").fileURLToPath(import.meta.url))` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(false) - }) - - test("handles extra whitespace in assignment", () => { - const bundle = `var __dirname = "/some/path/to/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("only patches FIRST match (non-global)", () => { - const bundle = [`var __dirname = "/first/path/python-bridge"`, `var __dirname = "/second/path/python-bridge"`].join( - "\n", - ) - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - // First one is patched - expect(result.output).toContain("import.meta.dirname") - // Second one survives — this is a known limitation - expect(result.output).toContain("/second/path/python-bridge") - }) - - test("does NOT match if quotes are single quotes", () => { - const bundle = `var __dirname = '/home/runner/python-bridge'` - const result = runPatchLogic(bundle) - // Bun uses double quotes, so single-quote paths should not match - expect(result.patched).toBe(false) - }) - - test("does NOT match let or const declarations", () => { - const bundle = `const __dirname = "/home/runner/python-bridge"` - const result = runPatchLogic(bundle) - // Pattern specifically matches `var __dirname` — const/let won't match - expect(result.patched).toBe(false) - }) -}) - -// ─── Adversarial: Built output invariants ─────────────────────────── -describe("adversarial: built bundle invariants", () => { - beforeAll(async () => { - // Ensure we have a fresh build - if (!existsSync(join(dist, "index.js"))) { - await $`bun run build`.cwd(join(import.meta.dir, "..")) - } - }) - - test("exactly ONE __dirname assignment exists in bundle", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - const matches = code.match(/var __dirname\s*=/g) - expect(matches).not.toBeNull() - expect(matches!.length).toBe(1) - }) - - test("__dirname is used to resolve PYTHON_BRIDGE_SCRIPT", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - expect(code).toContain('path.join(__dirname, "node_python_bridge.py")') - }) - - test("no CI runner paths leaked anywhere in bundle", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // Common CI runner path prefixes - expect(code).not.toContain("/home/runner/work/") - expect(code).not.toContain("/github/workspace/") - expect(code).not.toContain("D:\\a\\altimate-code\\") - }) - - test("patched __dirname includes both primary and fallback paths", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - const line = code.split("\n").find((l) => l.includes("var __dirname")) - expect(line).toBeDefined() - // Primary: import.meta.dirname - expect(line).toContain("import.meta.dirname") - // Fallback: fileURLToPath - expect(line).toContain("fileURLToPath") - // Uses __require (Bun's bundled require) - expect(line).toContain("__require") - }) - - test("node_python_bridge.py in dist matches the source", () => { - const resolved = require.resolve("@altimateai/dbt-integration") - const sourcePy = join(require("path").dirname(resolved), "node_python_bridge.py") - if (!existsSync(sourcePy)) return // skip if source not available - - const source = readFileSync(sourcePy, "utf8") - const copied = readFileSync(join(dist, "node_python_bridge.py"), "utf8") - expect(copied).toBe(source) - }) - - test("altimate_python_packages directory was copied", () => { - expect(existsSync(join(dist, "altimate_python_packages"))).toBe(true) - }) -}) - -// ─── Adversarial: Runtime resolution simulation ───────────────────── -describe("adversarial: runtime resolution", () => { - test("patched __dirname evaluates to a real directory at runtime", () => { - // import.meta.dirname should resolve to THIS test file's directory - // In the real bundle, it would resolve to dist/ - const dirname = import.meta.dir - expect(typeof dirname).toBe("string") - expect(dirname.length).toBeGreaterThan(0) - // Validate it's an actual directory, not a stale/hardcoded path - expect(existsSync(dirname)).toBe(true) - }) - - test("node_python_bridge.py is findable relative to dist/index.js", () => { - // This is the critical runtime check: __dirname should be dist/, - // and node_python_bridge.py should be in dist/ - const bridgePath = join(dist, "node_python_bridge.py") - expect(existsSync(bridgePath)).toBe(true) - - // Verify it's actually a Python file, not garbage - const content = readFileSync(bridgePath, "utf8") - expect(content).toContain("import") // Python imports - expect(content.length).toBeGreaterThan(100) // not truncated - }) - - test("bundle can be loaded from a DIFFERENT directory without path errors", async () => { - // Simulate running the binary from /tmp — __dirname should still - // resolve to where index.js lives, not the CWD - const tmpDir = mkdtempSync(join(tmpdir(), "adversarial-")) - const originalCwd = process.cwd() - - try { - process.chdir(tmpDir) - - // The patched code uses import.meta.dirname which is compile-time - // resolved to the file's actual location, not CWD. Verify this. - const indexPath = join(dist, "index.js") - expect(existsSync(indexPath)).toBe(true) - - // Read the bundle and verify the __dirname line doesn't reference CWD - const code = readFileSync(indexPath, "utf8") - expect(code).not.toContain(tmpDir) - } finally { - process.chdir(originalCwd) - } - }) -}) - -// ─── Adversarial: Double-patch protection ─────────────────────────── -describe("adversarial: idempotency", () => { - test("running the patch twice does not corrupt the bundle", () => { - const original = `var __dirname = "/ci/path/python-bridge"` - - // First patch - const first = runPatchLogic(original) - expect(first.patched).toBe(true) - - // Second patch on already-patched output — should be a no-op - const second = runPatchLogic(first.output) - expect(second.patched).toBe(false) - expect(second.output).toBe(first.output) - }) - - test("patch output is syntactically valid JS", () => { - const bundle = `var __dirname = "/home/runner/python-bridge";` - const result = runPatchLogic(bundle) - - // The patched code should not have unmatched quotes or parens - const openParens = (result.output.match(/\(/g) || []).length - const closeParens = (result.output.match(/\)/g) || []).length - expect(openParens).toBe(closeParens) - - const openQuotes = (result.output.match(/"/g) || []).length - expect(openQuotes % 2).toBe(0) // even number of quotes - }) -}) - -// ─── Adversarial: CI smoke test alignment ─────────────────────────── -describe("adversarial: CI smoke test parity", () => { - test("CI regex catches what build-integrity test catches", () => { - // CI uses: grep -qE 'var __dirname\\s*=\\s*"(/|[A-Za-z]:\\\\)' (shell regex) - // Test uses: /var __dirname\s*=\s*"(?:[A-Za-z]:\\\\|\/)/ - // Both should flag the same hardcoded paths - - const linuxPath = `var __dirname = "/home/runner/python-bridge"` - const windowsPath = `var __dirname = "C:\\\\Users\\\\runner\\\\python-bridge"` - const patchedPath = `var __dirname = typeof import.meta.dirname === "string" ? import.meta.dirname : __require("path").dirname(__require("url").fileURLToPath(import.meta.url))` - - const ciRegex = /var __dirname\s*=\s*"(\/|[A-Za-z]:\\)/ - const testRegex = /var __dirname\s*=\s*"(?:[A-Za-z]:\\\\|\/)/ - - // Both should flag hardcoded paths - expect(ciRegex.test(linuxPath)).toBe(true) - expect(testRegex.test(linuxPath)).toBe(true) - - expect(ciRegex.test(windowsPath)).toBe(true) - expect(testRegex.test(windowsPath)).toBe(true) - - // Neither should flag the patched version - expect(ciRegex.test(patchedPath)).toBe(false) - expect(testRegex.test(patchedPath)).toBe(false) - }) -}) - -// ─── Adversarial: copy-python.ts script execution ─────────────────── -describe("adversarial: copy-python.ts as a real script", () => { - test("build script exits 0 on success", async () => { - const result = await $`bun run build`.cwd(join(import.meta.dir, "..")).nothrow() - expect(result.exitCode).toBe(0) - expect(result.stderr.toString()).not.toContain("ERROR") - }) - - test("build script prints all three progress lines", async () => { - const result = await $`bun run build`.cwd(join(import.meta.dir, "..")).nothrow() - const output = result.stderr.toString() + result.stdout.toString() - expect(output).toContain("Copied altimate_python_packages") - expect(output).toContain("Copied node_python_bridge.py") - expect(output).toContain("Patched __dirname") - }) - - test("consecutive builds produce identical dist/index.js", async () => { - await $`bun run build`.cwd(join(import.meta.dir, "..")) - const first = readFileSync(join(dist, "index.js"), "utf8") - - await $`bun run build`.cwd(join(import.meta.dir, "..")) - const second = readFileSync(join(dist, "index.js"), "utf8") - - expect(first).toBe(second) - }) -}) - -// ─── Adversarial: bundle runtime structure ────────────────────────── -describe("adversarial: bundle runtime structure", () => { - beforeAll(async () => { - if (!existsSync(join(dist, "index.js"))) { - await $`bun run build`.cwd(join(import.meta.dir, "..")) - } - }) - - test("__require is defined via createRequire (not a Bun-only global)", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // __require must be created from Node's standard createRequire - expect(code).toContain('import { createRequire } from "node:module"') - expect(code).toMatch(/var __require\s*=.*createRequire\(import\.meta\.url\)/) - }) - - test("__dirname lives inside __commonJS wrapper (correct scope)", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // Find the python-bridge module wrapper - const bridgeStart = code.indexOf("// ../../node_modules/.bun/python-bridge") - expect(bridgeStart).toBeGreaterThan(-1) - - const dirnamePos = code.indexOf("var __dirname", bridgeStart) - expect(dirnamePos).toBeGreaterThan(bridgeStart) - - // __dirname should come BEFORE PYTHON_BRIDGE_SCRIPT in the same scope - const bridgeScriptPos = code.indexOf("PYTHON_BRIDGE_SCRIPT", dirnamePos) - expect(bridgeScriptPos).toBeGreaterThan(dirnamePos) - }) - - test("PYTHON_BRIDGE_SCRIPT resolves node_python_bridge.py via __dirname", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // The bridge script path must use __dirname, not a hardcoded path - expect(code).toMatch(/PYTHON_BRIDGE_SCRIPT\s*=\s*path\.join\(__dirname,\s*"node_python_bridge\.py"\)/) - }) - - test("python bridge spawn uses PYTHON_BRIDGE_SCRIPT variable", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // The spawn call must use the variable, not an inline path - expect(code).toContain("spawn(intepreter, [PYTHON_BRIDGE_SCRIPT]") - }) - - test("no other hardcoded python-bridge paths survive in bundle", () => { - const code = readFileSync(join(dist, "index.js"), "utf8") - // After patching, the only python-bridge references should be: - // 1. The comment line (// ../../node_modules/.bun/python-bridge@...) - // 2. The require_python_bridge function name - // 3. String literals for error messages - // There should be NO hardcoded filesystem paths to python-bridge - const lines = code.split("\n") - for (const line of lines) { - if (line.includes("python-bridge") && !line.trimStart().startsWith("//")) { - // This line references python-bridge — it must NOT be a hardcoded path - expect(line).not.toMatch(/["'](\/|[A-Z]:\\)[^"']*python-bridge/) - } - } - }) -}) - -// ─── Adversarial: publish pipeline ────────────────────────────────── -describe("adversarial: publish.ts copies patched artifacts", () => { - beforeAll(async () => { - if (!existsSync(join(dist, "index.js"))) { - await $`bun run build`.cwd(join(import.meta.dir, "..")) - } - }) - - test("dist/index.js is patched BEFORE publish.ts copies it", () => { - // publish.ts calls `bun run build` on dbt-tools, then copies dist/index.js. - // If copy-python.ts runs as part of build, the copied file must be patched. - const code = readFileSync(join(dist, "index.js"), "utf8") - expect(code).toContain("import.meta.dirname") - expect(code).not.toMatch(/var __dirname\s*=\s*"(?:[A-Za-z]:\\\\|\/)/) - }) - - test("dist/node_python_bridge.py is non-empty and valid Python", () => { - const py = readFileSync(join(dist, "node_python_bridge.py"), "utf8") - expect(py.length).toBeGreaterThan(500) // real file, not a stub - // Must contain the IPC message handling that the JS bridge talks to - expect(py).toContain("def") - // Must handle the JSON-RPC protocol - expect(py).toMatch(/json|JSON/) - }) -}) - -// ─── Adversarial: mutation testing (what if the fix is removed?) ───── -describe("adversarial: mutation testing", () => { - test("unpatched bundle WOULD contain a hardcoded absolute path", () => { - // Build raw bundle WITHOUT running copy-python.ts - // We simulate this by checking what bun build alone produces - const code = readFileSync(join(dist, "index.js"), "utf8") - - // The patched line should exist — if we remove the patch, the hardcoded - // path would return. Verify the patch is structurally present. - const patchedLine = code.split("\n").find((l) => l.includes("var __dirname") && l.includes("import.meta.dirname")) - expect(patchedLine).toBeDefined() - - // The patched line must have the ternary structure - expect(patchedLine).toContain("typeof import.meta.dirname") - expect(patchedLine).toContain("?") - expect(patchedLine).toContain(":") - expect(patchedLine).toContain("__require") - }) - - test("removing import.meta.dirname from replacement would break detection", () => { - // The CI smoke test and build-integrity test both look for "import.meta.dirname". - // If someone changes the replacement string to not include it, both guards catch it. - const brokenReplacement = `var __dirname = __require("path").dirname(__require("url").fileURLToPath(import.meta.url))` - // build-integrity.test.ts check: - expect(brokenReplacement).not.toContain("import.meta.dirname") - // This WOULD fail the integrity test — proving the guard works - }) - - test("removing the existence check would crash on missing bridge file", () => { - // Verify the existence check is actually in the script - const script = readFileSync(join(scriptDir, "copy-python.ts"), "utf8") - expect(script).toContain("existsSync(bridgePy)") - expect(script).toContain("process.exit(1)") - }) -}) - -// ─── Adversarial: regex catastrophic backtracking ─────────────────── -describe("adversarial: regex performance", () => { - test("patch regex does not catastrophically backtrack on large input", () => { - // Craft a pathological input that could cause ReDoS with a bad regex - const huge = `var __dirname = "${"a".repeat(100_000)}"` - const start = performance.now() - runPatchLogic(huge) - const elapsed = performance.now() - start - // Must complete in under 100ms even on 100KB input - expect(elapsed).toBeLessThan(100) - }) - - test("patch regex handles bundle with many var declarations", () => { - // Simulate a large bundle with thousands of var declarations - const lines = Array.from({ length: 10_000 }, (_, i) => `var x${i} = "${i}";`) - lines.push(`var __dirname = "/ci/path/python-bridge"`) - lines.push(`var PYTHON_BRIDGE_SCRIPT = path.join(__dirname, "node_python_bridge.py");`) - const bundle = lines.join("\n") - - const start = performance.now() - const result = runPatchLogic(bundle) - const elapsed = performance.now() - start - - expect(result.patched).toBe(true) - expect(elapsed).toBeLessThan(200) // reasonable for 10K lines - }) -}) - -// ─── Adversarial: path injection / malformed paths ────────────────── -describe("adversarial: malformed inputs", () => { - test("regex handles path with special regex characters", () => { - // Paths with characters that are special in regex: . + * ? [ ] ( ) - const bundle = `var __dirname = "/home/runner/work/node_modules/.bun/python-bridge@1.1.0+build.123/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("regex handles path with unicode characters", () => { - const bundle = `var __dirname = "/home/用户/项目/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("regex handles path with spaces", () => { - const bundle = `var __dirname = "/home/runner/my project/node_modules/python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("regex handles empty path with python-bridge", () => { - const bundle = `var __dirname = "python-bridge"` - const result = runPatchLogic(bundle) - expect(result.patched).toBe(true) - }) - - test("patch does NOT corrupt surrounding code", () => { - const before = `console.log("before");\n` - const target = `var __dirname = "/ci/python-bridge";\n` - const after = `var SCRIPT = path.join(__dirname, "bridge.py");\n` - const bundle = before + target + after - - const result = runPatchLogic(bundle) - // Before and after lines must survive untouched - expect(result.output).toContain(`console.log("before");`) - expect(result.output).toContain(`var SCRIPT = path.join(__dirname, "bridge.py");`) - // Target line is replaced - expect(result.output).toContain("import.meta.dirname") - expect(result.output).not.toContain("/ci/python-bridge") - }) - - test("patch preserves semicolons and line structure", () => { - const bundle = `var __dirname = "/ci/python-bridge";` - const result = runPatchLogic(bundle) - // The replacement should end where the original ended - // Original: var __dirname = "..."; → var __dirname = typeof ...; - // The semicolon after the closing quote is NOT part of the match, - // so it should survive - expect(result.output).toMatch(/\);$/) - }) -}) diff --git a/packages/dbt-tools/test/build-integrity.test.ts b/packages/dbt-tools/test/build-integrity.test.ts index f2bb589a09..9997193cbd 100644 --- a/packages/dbt-tools/test/build-integrity.test.ts +++ b/packages/dbt-tools/test/build-integrity.test.ts @@ -1,6 +1,6 @@ import { describe, test, expect, beforeAll } from "bun:test" import { existsSync, readFileSync } from "fs" -import { join } from "path" +import { dirname, join } from "path" import { $ } from "bun" const dist = join(import.meta.dir, "../dist") @@ -21,8 +21,14 @@ describe("build integrity", () => { expect(code).not.toMatch(/var __dirname\s*=\s*"(?:[A-Za-z]:\\\\|\/)/) }) - test("__dirname is patched to runtime resolution", () => { + test("the bridge script resolves relative to the bundle at runtime", () => { const code = readFileSync(join(dist, "index.js"), "utf8") - expect(code).toContain("import.meta.dirname") + expect(code).toContain("fileURLToPath(import.meta.url)") + expect(code).toContain(`"node_python_bridge.py"`) + }) + + test("node_python_bridge.py in dist is dbt-integration's copy", () => { + const shipped = join(dirname(require.resolve("@altimateai/dbt-integration")), "node_python_bridge.py") + expect(readFileSync(join(dist, "node_python_bridge.py"), "utf8")).toBe(readFileSync(shipped, "utf8")) }) }) diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index a5e3830959..7b251b90d7 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -73,8 +73,10 @@ async function copyAssets(targetDir: string) { await $`cp ../dbt-tools/bin/altimate-dbt ${targetDir}/dbt-tools/bin/altimate-dbt` await $`mkdir -p ${targetDir}/dbt-tools/dist` await $`cp ../dbt-tools/dist/index.js ${targetDir}/dbt-tools/dist/` - // node_python_bridge.py must live next to index.js — the patched __dirname - // resolves to this directory at runtime (see copy-python.ts) + // altimate_change start — dbt-integration's vendored bridge finds its script at runtime + // node_python_bridge.py must live next to index.js — dbt-integration resolves + // it from the bundle's own location at runtime (see copy-python.ts) + // altimate_change end await $`cp ../dbt-tools/dist/node_python_bridge.py ${targetDir}/dbt-tools/dist/` // A package.json with "type": "module" must be present so Node loads // dist/index.js as ESM instead of CJS. We synthesize a minimal one rather