Repository navigation
fix(agent-setup): stop agent wrappers from resolving themselves as the real binary #9489
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
base: main
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -5,9 +5,19 @@ import { ARTIFACT_GUARD_SCRIPT_NAME } from "./artifact-guard-hook"; | |
| import { NOTIFY_SCRIPT_NAME } from "./notify-hook"; | ||
| import { getBinDir } from "./paths"; | ||
|
|
||
| export const WRAPPER_MARKER = "# Superset agent-wrapper v5"; | ||
| export { SUPERSET_MANAGED_BINARIES }; | ||
|
|
||
| export const WRAPPER_MARKER_PREFIX = "# Superset agent-wrapper"; | ||
| export const WRAPPER_MARKER = `${WRAPPER_MARKER_PREFIX} v5`; | ||
|
|
||
| /** Wrapper passes allowed per binary in one process tree before it refuses to run. */ | ||
| export const MAX_WRAPPER_NESTING = 8; | ||
| export const WRAPPER_LOOP_EXIT_STATUS = 126; | ||
|
|
||
| export function getWrapperDepthVar(binaryName: string): string { | ||
| return `SUPERSET_WRAPPER_DEPTH_${binaryName.replace(/[^A-Za-z0-9]/g, "_")}`; | ||
| } | ||
|
|
||
| /** Path (under SUPERSET_HOME_DIR) of the runtime notify hook script. */ | ||
| export const MANAGED_NOTIFY_RELATIVE_PATH = `hooks/${NOTIFY_SCRIPT_NAME}`; | ||
|
|
||
|
|
@@ -117,26 +127,58 @@ export function isManagedArtifactGuardCommand( | |
| ); | ||
| } | ||
|
|
||
| /** | ||
| * A candidate is never the real binary when it is this wrapper (`-ef` follows | ||
| * symlinks, so aliased bin dirs, links elsewhere on PATH and relative or | ||
| * duplicate entries all match) or any other Superset wrapper, found by the | ||
| * marker on its second line. Neither check depends on HOME or on where the | ||
| * wrapper was generated. | ||
| */ | ||
| function buildRealBinaryResolver(): string { | ||
| return `find_real_binary() { | ||
| local name="$1" | ||
| local IFS=: | ||
| local dir candidate first_line marker_line | ||
| for dir in $PATH; do | ||
| [ -z "$dir" ] && continue | ||
| dir="\${dir%/}" | ||
| case "$dir" in | ||
| "${getBinDir()}"|"$HOME"/.paradev/bin|"$HOME"/.paradev-*/bin|"$HOME"/.superset/bin|"$HOME"/.superset-*/bin) continue ;; | ||
| esac | ||
| if [ -x "$dir/$name" ] && [ ! -d "$dir/$name" ]; then | ||
| printf "%s\\n" "$dir/$name" | ||
| return 0 | ||
| fi | ||
| candidate="$dir/$name" | ||
| [ -x "$candidate" ] && [ ! -d "$candidate" ] || continue | ||
| [ "$candidate" -ef "$0" ] && continue | ||
| marker_line="" | ||
| { IFS= read -r -n 256 first_line; IFS= read -r -n 256 marker_line; } 2>/dev/null <"$candidate" | ||
| case "$marker_line" in | ||
| "${WRAPPER_MARKER_PREFIX}"*) continue ;; | ||
| esac | ||
| printf "%s\\n" "$candidate" | ||
| return 0 | ||
| done | ||
| return 1 | ||
| } | ||
| `; | ||
| } | ||
|
|
||
| /** | ||
| * Last line of defense if the resolver ever lets the wrapper find itself: the | ||
| * counter lives in the environment, which every re-entry inherits (child or | ||
|
Contributor
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. P3: This comment overstates the depth guard. Only children and exec'd processes that keep the environment inherit the counter, so a child spawned with a scrubbed env restarts at depth 0. Reword it to say the guard covers re-entry through inherited environments. Prompt for AI agents |
||
| * exec), so the loop ends after a few passes with a clear message. | ||
| */ | ||
| function buildLoopGuard(binaryName: string): string { | ||
| const depthVar = getWrapperDepthVar(binaryName); | ||
| return `_superset_depth="\${${depthVar}:-0}" | ||
| case "$_superset_depth" in *[!0-9]*) _superset_depth=0 ;; esac | ||
| if [ "$_superset_depth" -ge ${MAX_WRAPPER_NESTING} ]; then | ||
| echo "Paradev: ${binaryName} wrapper re-entered itself ${MAX_WRAPPER_NESTING} times; a PATH entry resolves ${binaryName} back to this wrapper ($0). Remove it from PATH." >&2 | ||
| exit ${WRAPPER_LOOP_EXIT_STATUS} | ||
| fi | ||
| export ${depthVar}=$((10#$_superset_depth + 1)) | ||
|
Contributor
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.
|
||
|
|
||
| `; | ||
| } | ||
|
|
||
| /** | ||
| * Shell block that re-resolves the Usage-tab default account at launch. | ||
| * The PTY env is frozen at terminal spawn, so an account switch would | ||
|
|
@@ -259,7 +301,7 @@ ${buildLaunchReportBlock()}fi | |
| ${WRAPPER_MARKER} | ||
| # Superset wrapper for ${binaryName} | ||
|
|
||
| ${buildRealBinaryResolver()} | ||
| ${buildLoopGuard(binaryName)}${buildRealBinaryResolver()} | ||
| REAL_BIN="$(find_real_binary "${binaryName}")" | ||
| if [ -z "$REAL_BIN" ]; then | ||
| echo "${getMissingBinaryMessage(binaryName)}" >&2 | ||
|
|
||
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.
Script executed:
Repository: ParadevAI/Paradev
Length of output: 26393
Script executed:
Repository: ParadevAI/Paradev
Length of output: 42292
Script executed:
Repository: ParadevAI/Paradev
Length of output: 6792
Script executed:
Repository: ParadevAI/Paradev
Length of output: 2868
Web query:
github ParadevAI Paradev "Superset agent-wrapper" v2 agent-wrappers-common.tsResult:
Script executed:
Repository: ParadevAI/Paradev
Length of output: 3543
Script executed:
Repository: ParadevAI/Paradev
Length of output: 1248
Script executed:
Repository: ParadevAI/Paradev
Length of output: 10947
Script executed:
Repository: ParadevAI/Paradev
Length of output: 4699
Script executed:
Repository: ParadevAI/Paradev
Length of output: 2918
Script executed:
Repository: ParadevAI/Paradev
Length of output: 17689
Script executed:
Repository: ParadevAI/Paradev
Length of output: 2717
Script executed:
Repository: ParadevAI/Paradev
Length of output: 3332
Recognize pre-v1 wrappers during resolution.
An older wrapper without the marker can be selected from another app home. If its saved binary path later points to this wrapper, the two wrappers recurse until the depth guard exits 126. Recognize the older wrapper signature before selecting a candidate.