Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,35 @@ permissions:
contents: read

jobs:
gitleaks:
name: Gitleaks
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Scan repository history
run: >-
docker run --rm
-v "$PWD:/repo"
ghcr.io/gitleaks/gitleaks:v8.30.1
detect --source /repo --config /repo/.gitleaks.toml
--no-banner --redact --verbose

dependency-audit:
name: Dependency audit
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6

- uses: google/osv-scanner-action/osv-scanner-action@v2.3.8
with:
scan-args: |-
--config=osv-scanner.toml
--recursive
./

check:
runs-on: ubuntu-24.04
steps:
Expand All @@ -24,6 +53,9 @@ jobs:
- name: Typecheck
run: bun run typecheck

- name: Lint
run: bun run lint

- name: Test
run: bun run test

Expand Down
7 changes: 7 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[extend]
useDefault = true

[[allowlists]]
description = "Synthetic AWS key used by the sanitizer regression test"
paths = ['''packages/sync/test/sanitizer\.test\.ts''']
regexes = ['''AKIA1234567890ABCDEF''']
158 changes: 158 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions eslint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";

export default defineConfig(
{
ignores: ["coverage/**", "packages/**/dist/**"],
},
{
files: ["packages/**/*.ts", "vitest.config.ts"],
languageOptions: {
parser: tseslint.parser,
},
rules: {
complexity: ["error", 15],
"max-depth": ["error", 4],
"max-lines-per-function": [
"error",
{ max: 100, skipBlankLines: true, skipComments: true },
],
},
},
{
files: ["packages/**/*.test.ts"],
rules: {
"max-lines-per-function": "off",
},
},
);
4 changes: 4 additions & 0 deletions osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[[IgnoredVulns]]
id = "GHSA-g7r4-m6w7-qqqr"
ignoreUntil = 2026-10-23
reason = "Low-severity esbuild development-server advisory; v1 blocks high/critical. Tracked in #57."
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
"test:supabase": "supabase test db supabase/tests/database --local && bun run supabase/tests/welcome-credits-concurrency.ts && bun test packages/billing/test/checkout-lifecycle.contract.test.ts && bun test packages/sync/test/lww.contract.test.ts && bun test packages/edge-shared/test/router-attempt.contract.test.ts",
"test:coverage": "vitest run --coverage",
"typecheck": "tsc -p tsconfig.json --noEmit",
"check": "bun run typecheck && bun run test && bun run test:coverage && bun run build"
"lint": "eslint packages vitest.config.ts",
"check": "bun run typecheck && bun run lint && bun run test && bun run test:coverage && bun run build"
},
"devDependencies": {
"@types/bun": "^1.3.5",
"@types/node": "^24.10.1",
"@vitest/coverage-v8": "^4.0.14",
"eslint": "^10.7.0",
"happy-dom": "^20.8.4",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.65.0",
"vitest": "^4.0.14"
}
}
1 change: 1 addition & 0 deletions packages/auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ interface EntitlementCache {

const DEFAULT_ENTITLEMENT_CACHE_TTL_MS = 5 * 60 * 1000;

// eslint-disable-next-line max-lines-per-function -- TODO(#57): split the legacy client factory.
export function createPickforgeAuthClient(config: PickforgeAuthConfig): PickforgeAuthClient {
validateConfig(config);

Expand Down
2 changes: 2 additions & 0 deletions packages/billing/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ async function processCheckoutSessionMoneyEvent({
return { handled: true, duplicate: false };
}

// eslint-disable-next-line max-lines-per-function -- TODO(#57): split the legacy refund lifecycle flow.
async function processRefundLifecycleEvent({
supabase,
stripe,
Expand Down Expand Up @@ -605,6 +606,7 @@ async function reconcileRefundLifecycleEvent(
return data;
}

// eslint-disable-next-line complexity, max-lines-per-function -- TODO(#57): split the legacy deletion refund flow.
async function performDeletionRefund({
supabase,
stripe,
Expand Down
1 change: 1 addition & 0 deletions packages/billing/test/billing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ class MemorySupabase implements SupabaseClientLike {
return null;
}

// eslint-disable-next-line complexity -- TODO(#57): split the legacy lifecycle fake dispatcher.
async rpc<T = unknown>(fn: string, args?: Record<string, unknown>): Promise<SupabaseQueryResult<T>> {
if (fn === "checkout_lifecycle_reconcile_completion") {
const sessionId = String(args?.checkout_session_id);
Expand Down
4 changes: 4 additions & 0 deletions packages/edge-shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ export function assertRouteRequest(body: unknown): RouteRequest {
return context === undefined ? { commandText } : { commandText, context };
}

// eslint-disable-next-line max-lines-per-function -- TODO(#57): split the legacy router handler factory.
export function createOperatorRouterHandler({
supabase,
serviceSupabase,
Expand All @@ -669,6 +670,7 @@ export function createOperatorRouterHandler({
const validBaseUrl = validateNonEmptyString(baseUrl, "baseUrl", "invalid_string");
const validCreditCostCents = validatePositiveInteger(creditCostCents, "creditCostCents");

// eslint-disable-next-line max-lines-per-function -- TODO(#57): split the legacy router request flow.
return async (req: Request): Promise<Response> => {
try {
const { userId } = await getUserFromRequest({ supabase, req });
Expand Down Expand Up @@ -884,6 +886,7 @@ export function createDeleteAccountHandler({
stripe,
resolveUserId,
}: CreateDeleteAccountHandlerOptions): (req: Request) => Promise<Response> {
// eslint-disable-next-line complexity -- TODO(#57): split the legacy account deletion flow.
return async (req: Request): Promise<Response> => {
try {
const userId = await resolveUserId(req);
Expand Down Expand Up @@ -1221,6 +1224,7 @@ function hasOnlyKeys(value: Record<string, unknown>, allowed: string[]): boolean
return Object.keys(value).every((key) => allowed.includes(key));
}

// eslint-disable-next-line complexity -- TODO(#57): replace the legacy identifier matcher with data-driven checks.
function containsForbiddenIdentifier(value: string): boolean {
return (
/\b[a-z][a-z0-9+.-]*:\/\//i.test(value) ||
Expand Down
1 change: 1 addition & 0 deletions packages/edge-shared/test/edge-shared.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,7 @@ function accountAdmin(
from<T = unknown>(table: string): AccountQuery<T> {
return new AccountQuery<T>(rows[table] ?? [], errors[table] ?? null);
},
// eslint-disable-next-line complexity -- TODO(#57): split the legacy lifecycle fake dispatcher.
async rpc<T = unknown>(
fn: string,
args?: Record<string, unknown>,
Expand Down
1 change: 1 addition & 0 deletions packages/sync/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ function walkPayload(group: SyncFieldGroup, value: Json, path: string[]): void {
}
}

// eslint-disable-next-line complexity -- TODO(#57): split the legacy sync boundary validator.
function assertAllowedString(group: SyncFieldGroup, value: string, key: string | undefined): void {
const text = value.trim();
const skipPathCheck = group === "remoteBindings" && key === "remoteRoot";
Expand Down
5 changes: 5 additions & 0 deletions packages/tauri-release/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ export function writeLatestJson(path: string, latest: LatestJson): void {
writeFileSync(path, `${JSON.stringify(latest, null, 2)}\n`);
}

// eslint-disable-next-line complexity -- TODO(#57): split the legacy AppImage repair flow.
export function fixAppImage(options: FixAppImageOptions): FixAppImageResult {
const env = options.env ?? process.env;
const signed = isSigningEnabled(env);
Expand Down Expand Up @@ -495,6 +496,7 @@ export function fixAppImage(options: FixAppImageOptions): FixAppImageResult {
}
}

// eslint-disable-next-line complexity -- TODO(#57): split the legacy updater feed validator.
export function verifyLatestJson(input: string | LatestJson): LatestJsonVerification {
const errors: string[] = [];
let parsed: unknown = null;
Expand Down Expand Up @@ -541,8 +543,10 @@ export function verifyLatestJson(input: string | LatestJson): LatestJsonVerifica
if (!isNonEmptyString(platformRecord.url)) {
errors.push(`${platform}.url must be a non-empty string`);
} else {
// eslint-disable-next-line max-depth -- TODO(#57): flatten the legacy feed URL validation.
try {
const url = new URL(platformRecord.url);
// eslint-disable-next-line max-depth -- TODO(#57): flatten the legacy feed URL validation.
if (url.protocol !== "https:" && url.protocol !== "http:") {
errors.push(`${platform}.url must use http or https`);
}
Expand Down Expand Up @@ -1182,6 +1186,7 @@ function formatToolOutput(output: string): string {
return trimmed.length === 0 ? "" : `: ${trimmed}`;
}

// eslint-disable-next-line complexity -- TODO(#57): replace legacy asset precedence branches with data.
function platformPriority(assetName: string, platform: PlatformKey): number {
const lowered = assetName.toLowerCase();
if (platform === "linux-x86_64" && lowered.endsWith(".appimage")) {
Expand Down
2 changes: 2 additions & 0 deletions packages/tauri-updater/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export function createEligibility(value: StaticEligibility): UpdateEligibility {
};
}

// eslint-disable-next-line max-lines-per-function -- TODO(#57): split the legacy update controller factory.
export function createUpdateController(options: {
adapter: UpdateAdapter;
eligibility: UpdateEligibility;
Expand All @@ -106,6 +107,7 @@ export function createUpdateController(options: {
const check = async ({
silent = false,
manual = false,
// eslint-disable-next-line complexity -- TODO(#57): split the legacy update check flow.
}: { silent?: boolean; manual?: boolean } = {}): Promise<void> => {
if (manual) {
if (isBusy(state)) return;
Expand Down
1 change: 1 addition & 0 deletions packages/tauri-updater/src/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export class PickforgeUpdateDialogElement extends HTMLElementBase {
return dialog;
}

// eslint-disable-next-line complexity -- TODO(#57): split the legacy updater element renderer.
#render(): void {
const state = this.#state;
if (!isVisibleState(state)) {
Expand Down
8 changes: 4 additions & 4 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export default defineConfig({
provider: "v8",
reporter: ["text", "html", "lcov"],
thresholds: {
branches: 64,
functions: 83,
lines: 72,
statements: 72,
branches: 67,
functions: 84,
lines: 75,
statements: 75,
},
},
include: ["packages/**/*.test.ts"],
Expand Down