Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fe8565b
feat(init): add iOS project inspection foundations
seanperez29 Aug 21, 2026
1a9cb68
fix(init): mask XML comments without joining markup
seanperez29 Aug 21, 2026
9cbea87
fix(init): normalize plist imports in bundled CLI
seanperez29 Aug 27, 2026
13827d1
fix(init): reject resolved non-iOS targets
seanperez29 Aug 27, 2026
5672fcb
fix(init): ignore Swift regex literal evidence
seanperez29 Aug 27, 2026
5aa8c57
fix(init): fail closed on skipped Xcode links
seanperez29 Aug 27, 2026
f458827
fix(init): preserve concurrent file replacements
seanperez29 Aug 27, 2026
f8c80ff
fix(init): inspect x86_64 simulator settings
seanperez29 Aug 27, 2026
833fab6
fix(init): preserve entitlement build contexts
seanperez29 Aug 27, 2026
081d13d
fix(init): filter inactive Xcode platforms
seanperez29 Aug 27, 2026
217d750
fix(init): preserve xcconfig continuations
seanperez29 Aug 27, 2026
4dfa955
fix(init): handle xcconfig continuation variants
seanperez29 Aug 27, 2026
118173f
fix(init): bind file mutations to prepared roots
seanperez29 Aug 27, 2026
9edcf6a
fix(init): restore claims after boundary changes
seanperez29 Aug 27, 2026
f7101ea
fix(init): select runtime keys from proven wiring
seanperez29 Aug 27, 2026
3054f76
fix(deps): override vulnerable xmldom version
seanperez29 Aug 27, 2026
d9d2b81
fix(init): preserve invalid Apple entitlements
seanperez29 Aug 28, 2026
1dfad68
fix(init): fail closed on incomplete scheme discovery
seanperez29 Aug 28, 2026
1927129
fix(init): propagate container discovery completeness
seanperez29 Aug 28, 2026
8fd1c01
fix(init): validate Clerk product attribution
seanperez29 Aug 28, 2026
589a0d3
fix(init): recover interrupted iOS file transactions
seanperez29 Aug 28, 2026
b948a7a
fix(init): keep iOS inspection read-only
seanperez29 Aug 28, 2026
7bc75cd
fix(init): require proven iOS key wiring
seanperez29 Aug 28, 2026
9d177c9
test: preload CLI version macro
seanperez29 Aug 28, 2026
83afb85
fix(init): strengthen iOS inspection evidence
seanperez29 Aug 28, 2026
9f20a13
fix(ios): traverse referenced Xcode projects
seanperez29 Aug 29, 2026
6f4cb24
fix(ios): bound project metadata reads
seanperez29 Aug 29, 2026
e40db4f
fix(init): bind scheme keys to launched target
seanperez29 Aug 29, 2026
b07bc77
refactor(ios): simplify custom key inspection
seanperez29 Aug 29, 2026
61a586f
refactor(ios): simplify publishable key state
seanperez29 Aug 29, 2026
de5f310
fix(init): harden Xcode path resolution
seanperez29 Aug 29, 2026
3fd4518
fix(init): reject malformed Xcode platform filters
seanperez29 Aug 29, 2026
22d83d7
fix(init): fail closed on interpolated Clerk calls
seanperez29 Aug 29, 2026
c28cb9c
fix(init): compare interpolated Clerk evidence
seanperez29 Aug 29, 2026
83b744b
fix(init): honor active Swift platform branches
seanperez29 Aug 29, 2026
04aac9e
fix(ios): fail closed on malformed source membership
seanperez29 Aug 30, 2026
4d325ba
fix(ios): validate Xcode source membership metadata
seanperez29 Aug 30, 2026
256833b
fix(ios): match entitlement bundle IDs case-insensitively
seanperez29 Aug 30, 2026
a7a7435
fix(ios): validate synchronized exclusions
seanperez29 Aug 30, 2026
e36b13e
fix(ios): validate synchronized exception records
seanperez29 Aug 31, 2026
47a8389
fix(init): reject malformed associated domains
seanperez29 Aug 31, 2026
d9cc0ef
fix(init): preserve unrelated entitlement evidence
seanperez29 Aug 31, 2026
b44751b
fix(init): preserve Swift division assignment
seanperez29 Aug 31, 2026
1caada1
fix(init): distrust conditional Swift evidence
seanperez29 Aug 31, 2026
2229d9a
docs(changeset): add native Apple project inspection
seanperez29 Aug 31, 2026
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
5 changes: 5 additions & 0 deletions .changeset/ios-project-inspector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"clerk": patch
---

Add safe Xcode project inspection for native Apple setup.
15 changes: 15 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[install]
# Only install package versions published at least 2 days ago
minimumReleaseAge = 172800

[test]
preload = ["./packages/cli-core/src/test/version-preload.ts"]
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"typescript": "^7"
},
"overrides": {
"@xmldom/xmldom": "0.8.15",
"tmp": "^0.2.6"
},
"nano-staged": {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
"test": "bun test src/ --parallel"
},
"dependencies": {
"@bacons/xcode": "1.0.0-alpha.33",
"@clack/prompts": "^1.7.0",
"@clerk/cli-extras": "workspace:*",
"@commander-js/extra-typings": "^15.0.0",
"@expo/plist": "0.0.18",
"@napi-rs/keyring": "^1.3.0",
"commander": "^15.0.0",
"env-paths": "^4.0.0",
Expand Down
58 changes: 58 additions & 0 deletions packages/cli-core/src/commands/init/ios/bounded-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { constants as fsConstants } from "node:fs";
import { open } from "node:fs/promises";

const READ_CHUNK_BYTES = 64 * 1024;

export type BoundedRegularFileReadResult =
| { status: "ok"; bytes: Uint8Array }
| { status: "missing" | "not-regular" | "too-large" | "unreadable" };

function missingPath(error: unknown): boolean {
if (!(error instanceof Error) || !("code" in error)) return false;
return error.code === "ENOENT" || error.code === "ENOTDIR";
}

/**
* Reads a regular file without letting special files block the process or a
* concurrently growing file exceed the caller's memory bound. Type, size,
* and bytes all come from the same descriptor so a replacement at the path
* cannot invalidate the checks performed before the read.
*/
export async function readBoundedRegularFile(
path: string,
maxBytes: number,
): Promise<BoundedRegularFileReadResult> {
let handle;
try {
handle = await open(
path,
fsConstants.O_RDONLY | fsConstants.O_NONBLOCK | fsConstants.O_NOFOLLOW,
);
} catch (error) {
return { status: missingPath(error) ? "missing" : "unreadable" };
}

try {
const info = await handle.stat();
if (!info.isFile()) return { status: "not-regular" };
if (info.size > maxBytes) return { status: "too-large" };

const chunks: Uint8Array[] = [];
let totalBytes = 0;
while (true) {
const bytesUntilOverflow = maxBytes - totalBytes + 1;
const chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, bytesUntilOverflow));
const { bytesRead } = await handle.read(chunk, 0, chunk.byteLength, totalBytes);
if (bytesRead === 0) break;
totalBytes += bytesRead;
if (totalBytes > maxBytes) return { status: "too-large" };
chunks.push(chunk.subarray(0, bytesRead));
}

return { status: "ok", bytes: Buffer.concat(chunks, totalBytes) };
} catch {
return { status: "unreadable" };
} finally {
await handle.close().catch(() => undefined);
}
}
Loading