-
Notifications
You must be signed in to change notification settings - Fork 0
rt-tray: fix the bundle seal, prune node, and make bundled apps mattstack-managed #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,8 +180,11 @@ fi | |
| HELPER_ENTITLEMENTS=() # "path<TAB>jit|none" for the signing pass | ||
| bundle_helpers() { | ||
| if [ ! -d "$DEPS_DIR" ]; then | ||
| if [ "${RT_REQUIRE_DEPS:-0}" = 1 ]; then echo " ✗ $DEPS_DIR missing — run scripts/fetch-deps.sh arm64"; exit 1; fi | ||
| echo " ⚠ $DEPS_DIR missing — Helpers skipped (scripts/fetch-deps.sh arm64 to bundle them)" | ||
| # Fatal by default: a warn-and-continue here silently produces a bundle | ||
| # with NO helpers, which then passes every gate that only asserts the | ||
| # helpers it can find. Set RT_REQUIRE_DEPS=0 to opt out deliberately. | ||
| if [ "${RT_REQUIRE_DEPS:-1}" = 1 ]; then echo " ✗ $DEPS_DIR missing — run scripts/fetch-deps.sh arm64 (RT_REQUIRE_DEPS=0 to build without helpers)"; exit 1; fi | ||
| echo " ⚠ $DEPS_DIR missing — Helpers skipped (RT_REQUIRE_DEPS=0 set)" | ||
| return | ||
| fi | ||
| local row name version bundlePath ent status src dest prune | ||
|
|
@@ -216,6 +219,19 @@ bundle_helpers() { | |
| rm -rf "$prune" | ||
| echo " · pruned $name/${prune#"$dest"/}" | ||
| done < <(find "$dest" -depth -type d \( -name '.claude-plugin' -o -name '.codex-plugin' \) -print0) | ||
| # node ships a full development distribution, but the bundle needs it | ||
| # only to run fast-browser's .mjs. include/ is 2726 C++ headers node-gyp | ||
| # uses to compile native addons at build time; lib/node_modules/{npm, | ||
| # corepack} and their bin/ symlinks are unreferenced here. Beyond the | ||
| # ~78MB, every file under Contents/Helpers must be individually signed, | ||
| # so this dead weight also costs ~8 minutes of timestamp round-trips per | ||
| # release build (4708 files → ~61). The symlinks go too: a dangling one | ||
| # left behind breaks the outer seal. | ||
| if [ "$name" = node ]; then | ||
| rm -rf "$dest/include" "$dest/lib/node_modules/npm" "$dest/lib/node_modules/corepack" "$dest/share" | ||
| rm -f "$dest/bin/npm" "$dest/bin/npx" "$dest/bin/corepack" | ||
| echo " · pruned node/{include,lib/node_modules,share} (dev distribution, unused in-bundle)" | ||
| fi | ||
| HELPER_ENTITLEMENTS+=("$dest $ent") | ||
| echo " ✓ Helpers/$name $version" | ||
| done < "$tsv" | ||
|
|
@@ -339,19 +355,49 @@ if [ -d "$CORE_FW" ]; then | |
| echo " ✓ Signed MattstackCore.framework" | ||
| fi | ||
|
|
||
| sign_helper_tree() { # root ent — signs every Mach-O under root (files or a dir like node/) | ||
| local root="$1" ent="$2" f | ||
| # Everything under Contents/Helpers is classified as nested code by codesign's | ||
| # bundle seal — not just the Mach-O binaries — so every regular file here must | ||
| # carry a signature or the outer `sign "$APP_BUNDLE"` refuses with "code object | ||
| # is not signed at all / In subcomponent: <first unsigned file>". A pure-script | ||
| # helper (fast-browser: .mjs + LICENSE + package.json, zero Mach-O) has no | ||
| # binary to match, so a Mach-O-only pass signs nothing in it and the seal fails. | ||
| # Non-Mach-O files get a plain signature stored in an xattr; only real binaries | ||
| # take the JIT entitlement and the helper identifier. | ||
| sign_helper_tree() { # root ent — signs every regular file under root (files or a dir like node/) | ||
| local root="$1" ent="$2" f signed | ||
| signed=$(find "$root" -type f | wc -l | tr -d ' ') | ||
| # A helper that contributes zero files can only mean the tree was never | ||
| # staged — the seal would fail later and much less legibly. | ||
| [ "$signed" -gt 0 ] || { echo " ✗ $(basename "$root"): no files to sign under $root"; exit 1; } | ||
|
|
||
| # Pass 1 — plain-sign EVERY regular file, in parallel. codesign's bundle | ||
| # seal treats everything under Contents/Helpers as nested code, not just | ||
| # the Mach-O binaries, so a single unsigned file (a .mjs, a LICENSE, one of | ||
| # node/'s thousands of headers) makes the outer `sign "$APP_BUNDLE"` fail | ||
| # with "code object is not signed at all / In subcomponent: <that file>". | ||
| # Batched (many paths per codesign call), NOT `xargs -I{}`: the -I form | ||
| # runs one process per file, is ~6x slower, and was observed leaving files | ||
| # silently unsigned — which only surfaces later as an opaque outer-seal | ||
| # failure naming one arbitrary file. stderr is kept, not discarded: hiding | ||
| # it is what made the misses invisible the first time. | ||
| find "$root" -type f -print0 | xargs -0 -P 8 codesign "${SIGN_FLAGS[@]}" 2>&1 \ | ||
| | grep -v "replacing existing signature" || true | ||
|
Comment on lines
+383
to
+384
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Demonstrate that `|| true` masks a failed pipeline.
set -o pipefail
false | cat | grep -v 'replacing existing signature' || true
test "$?" -eq 0Repository: m4ttstack/rt Length of output: 150 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- target lines ---'
sed -n '330,410p' rt-tray/build.sh
printf '%s\n' '--- shell settings and signing references ---'
rg -n -C 4 'set -|pipefail|codesign|SIGN_FLAGS|signed|helper' rt-tray/build.sh
printf '%s\n' '--- executable context ---'
sed -n '1,40p' rt-tray/build.shRepository: m4ttstack/rt Length of output: 16314 🏁 Script executed: #!/bin/bash
set -u
# Reproduce xargs' failure status and the reviewed pipeline's status.
set -o pipefail
set +e
printf 'helper-file\0' |
xargs -0 -P 8 sh -c 'printf "codesign failed\n" >&2; exit 1' _ 2>&1 |
grep -v 'replacing existing signature'
pipeline_status=$?
pipeline_parts=("${PIPESTATUS[@]}")
set -e
printf 'pipeline_status=%s pipe_statuses=%s\n' \
"$pipeline_status" "${pipeline_parts[*]}"
# Show that the trailing `|| true` changes the compound command status.
set +e
set -o pipefail
printf 'helper-file\0' |
xargs -0 -P 8 sh -c 'exit 1' _ 2>&1 |
grep -v 'replacing existing signature' || true
masked_status=$?
set -e
printf 'masked_status=%s\n' "$masked_status"
# Confirm the relevant source conditions without executing the repository script.
printf '%s\n' '--- source assertions ---'
grep -nF 'set -euo pipefail' rt-tray/build.sh
grep -nF 'find "$root" -type f -print0 | xargs -0 -P 8 codesign "${SIGN_FLAGS[@]}"' rt-tray/build.sh
grep -nF 'echo " ✓ Signed Helpers/$(basename "$path") ($ent, $SIGNED_FILE_COUNT files)"' rt-tray/build.shRepository: m4ttstack/rt Length of output: 439 Propagate batch-signing failures. With 🤖 Prompt for AI Agents |
||
|
|
||
| # Pass 2 — re-sign just the Mach-O binaries with their identifier and | ||
| # entitlements, overwriting pass 1's plain signature. Must come second: | ||
| # whichever pass runs last is the signature that survives. | ||
| while IFS= read -r -d '' f; do | ||
| if file -b "$f" | grep -q "Mach-O"; then | ||
| if [ "$ent" = jit ]; then sign -i "com.mattstack.helper.$(basename "$f")" --entitlements "$ENTITLEMENTS_JIT" "$f" | ||
| else sign -i "com.mattstack.helper.$(basename "$f")" "$f"; fi | ||
| fi | ||
| done < <(find "$root" -type f -print0) | ||
| SIGNED_FILE_COUNT=$signed | ||
| } | ||
| for entry in "${HELPER_ENTITLEMENTS[@]+"${HELPER_ENTITLEMENTS[@]}"}"; do | ||
| path="${entry%% *}"; ent="${entry##* }" | ||
| sign_helper_tree "$path" "$ent" | ||
| echo " ✓ Signed Helpers/$(basename "$path") ($ent)" | ||
| echo " ✓ Signed Helpers/$(basename "$path") ($ent, $SIGNED_FILE_COUNT files)" | ||
| done | ||
|
|
||
| if [ -f "$CONTENTS/MacOS/rt" ]; then | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 33191
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 50370
🌐 Web query:
m4ttstack deck GitHub "deck add" "deck adopt" managedBy💡 Result:
There is no single, canonical software project simply called "m4ttstack deck" that implements "deck add," "deck adopt," or "managedBy" commands. The query appears to conflate several distinct CLI tools and ecosystem projects that share the word "deck" in their names or are associated with the "m4ttstack" GitHub organization. The "m4ttstack" organization on GitHub maintains a project called "rt" (a developer CLI with a daemon and tray app), not a general-purpose project called "deck" [1][2]. Regarding the specific commands and patterns you mentioned: 1. managedBy: This is a standard field used in Kubernetes and various infrastructure-as-code (IaC) tools to indicate which controller or system manages a resource. It is common in tools like Kong's decK (used for API lifecycle automation) [3] or Kubernetes operators, rather than a specific command in a "m4ttstack deck" tool. 2. deck add / deck adopt: These commands appear in different, unrelated projects: - Agent/Session Management: Projects like "agent-deck" (or "asheshgoplani-agent-deck") use "deck add" to add directories or sessions to an AI coding agent manager [4]. - Fleet Deck: "Fleet Deck" uses concepts like "adopt" in its internal gateway routing and session management logic, specifically for handling LLM gateway profiles [5][6]. - Deck (getdeck.io): This platform uses "claude mcp add" or "codex mcp add" to configure connections to its services, often involving MCP (Model Context Protocol) integration [7][8]. If you are trying to manage infrastructure or AI agent configurations, please verify the specific GitHub repository you are interacting with, as these commands belong to separate tools such as Kong's decK [3], agent-deck [4], or various AI-related plugins [7][8][6].
Citations:
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 50369
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 459
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 6016
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 289
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 50368
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 25674
🏁 Script executed:
Repository: m4ttstack/rt
Length of output: 13234
Reconcile the existing app configuration before adoption.
When
deck addreturns"name taken", Deck does not update the existing record.deck adoptchanges onlymanagedBy, so an oldergitqrecord can retain its bare command instead ofgitq board. UpdatecommandandworkingDirectorythrough the app PATCH endpoint before adoption, or reject mismatched collisions. Add a duplicate-registration test with the oldgitqcommand.🧰 Tools
🪛 OpenGrep (1.26.0)
[ERROR] 137-137: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🤖 Prompt for AI Agents