Visitar URL original
fix(rc.d): list ~/.rc.d with command ls in the login bridge by basiliskus · Pull Request #588 · GSA-TTS/agentic-coding-quickstart · GitHub
Skip to content

fix(rc.d): list ~/.rc.d with command ls in the login bridge - #588

Merged
wz-gsa merged 1 commit into
mainfrom
fix/rc-bridge-command-ls
Oct 19, 2026
Merged

wz-gsa merged 1 commit into
mainfrom
fix/rc-bridge-command-ls

Conversation

@basiliskus

Copy link
Copy Markdown
Contributor

Summary

The ~/.rc.d login bridge (acq_login_profile_rc_block) lists snippets with $(LC_ALL=C ls "$HOME"/.rc.d). The login ~/.profile sources ~/.bashrc before that block, so in an interactive login shell a user's ls alias or function is already in effect when the block runs. Depending on the alias, snippets run in the wrong order (ls -r), are skipped (ls -F on an executable snippet, ls -Q), or are found only because their names appear among the words of a long listing (ls -l).

This switches the listing to LC_ALL=C command ls, which bypasses aliases and functions. The C collation, guards, and line count of the block (and so the heal's max_lines bound) are unchanged.

Related Issues

Fixes #587

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Checklist

  • I have read CONTRIBUTING.md
  • My commits follow the Conventional Commits format (e.g., feat:, fix:, docs:)
  • I have tested my changes locally
  • I have updated documentation as needed
  • I have not included any secrets, API keys, or sensitive information

Test Results

  • New test rc.d: login-profile block ignores an ls alias or function from .bashrc (#587) (72-msb-agent-user.bats) runs the generated block with alias ls="ls -r" and, separately, an ls function that names one snippet twice and omits the other. Without the fix it fails (20-b then 10-a); with it, both cases source 10-a then 20-b.
  • The two tests that pin the bridge text (72-msb-agent-user.bats, 90-sbx-startup-kit.bats) now assert LC_ALL=C command ls.
  • bats --filter 'rc.d|#426' over both files: 14/14 pass. shellcheck -S warning acq.backends/common.sh: clean.
  • Full ./scripts/test-acq-bats: 730 pass, 12 fail. The same 10 fail on unmodified main in this environment (clone, msys, migration-gate, dispatch, github-scope, and msb provision tests), and the other 2 are the sbx grammar acceptance tests, which need sbx login.

The login ~/.profile sources ~/.bashrc before the rc.d block, so in an
interactive login shell a user's `ls` alias or function is already
defined when the block lists ~/.rc.d. Depending on the alias, snippets
then run in the wrong order (`ls -r`), are skipped (`ls -F` on an
executable snippet, `ls -Q`), or are found only because their names
appear among the words of a long listing (`ls -l`). `command ls` skips
aliases and functions; the C collation and the block's line count are
unchanged.

Fixes #587

@wz-gsa wz-gsa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-assisted review (OpenCode), verified independently against head dbbc874fc1300b5a8045f720b4d311601cf4f9a9.

Approving. I generated the emitted bridge text from both base and head and ran it under hostile shell state, including real bash -l and bash -il with an authentic msb-shaped ~/.profile and the hostile definition living in .bashrc.

The fix works, causally

All four interference modes from #587 reproduce on base and are fixed on head:

.bashrc holds base head
alias ls='ls -r' 20-b, 10-a 10-a, 20-b
alias ls='ls -F' with an executable snippet 20-b only 10-a, 20-b
alias ls='ls -Q' nothing sourced 10-a, 20-b
ls() { ... }, including export -f ls 20-b only 10-a, 20-b

Confirmed causally rather than by correlation: swapping the base common.sh into the head worktree makes the new test fail with exactly 20-b / 10-a, and restoring head makes it pass.

Line count and bounds are genuinely unchanged, checked byte-level rather than by inspection. The emitted block is 11 lines on both revisions, the diff of the two texts is exactly one line, and the derived bounds are identical: msb.sh:3970 3 + 11 = 14, sbx.sh:684 1 + 11 = 12. The upgrade path holds, since a profile written by the old bridge is still within max_lines and gets rewritten, and append-survival still holds at one appended line.

common.sh:1192 is the only ~/.rc.d listing in the repo. The doctor at common.sh:3596-3601 iterates literal paths and greps, and still matches the acq-login-profile marker against the new text.

The $BASH_VERSION gate at common.sh:1191 means the POSIX sh/dash login path is unaffected; under dash -c '. ~/.profile' the body never executes on either revision.

Checks

Focused bats --filter 'rc.d' over both files: 7/7. Both modified files in full: 37/37 and 21/21. shellcheck -S warning acq.backends/common.sh clean, and clean on both .bats files. CI on this head is green 5/5.

I ran these in a sanitized explicit environment with env -i, a pinned PATH, a private TMPDIR, and GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM pointed at /dev/null, after grepping both files specifically for the #569 nested-fixture-repo pattern. Neither file contains git init or git -C.

I did not run the full ./scripts/test-acq-bats, deliberately, given #569 and runtime. Your 730/12 figure and the 10-of-12 also-fail-on-main claim are therefore unverified by me. No live msb or sbx verification either; no backend is available here.

Two low-severity notes, neither blocking

command is itself shadowable. command() { echo 20-b.sh; } or alias command='echo 20-b.sh' in .bashrc passes on base and fails on head. command bypasses alias and function lookup for its argument, not for itself. This trades a near-universal interference vector for a rare one, so it is strongly net-positive, but the PR body's phrasing is broader than the behavior. Neither \command nor builtin command closes it; only a command-word-free form would. Also unchanged: a PATH-shim ls still wins, since command ls honors PATH, so the eza style replacement mentioned in the issue is only addressed in its alias form.

Unquoted command substitution still word-splits, pre-existing and unchanged. With .rc.d holding 10-a.sh, 50 space.sh, and space.sh, both revisions source 10-a, space, space: the spaced name never runs and an unrelated snippet is double-sourced. The charset guard at common.sh:1196 inspects post-split words, so it cannot catch this. It is unreachable through the sanctioned path, because kit_spec_files rejects both shapes at kit-translate.sh:561, which I verified with a real spec. Defense-in-depth gap only, introduced at 6a67063, untouched here.

Worth recording: ShellCheck flags the base bridge text as SC2045 when linted as the sh it becomes, and the head text does not. command ls silences that detector without removing the fragility it pointed at.

Optional, if you amend anyway

  1. Soften the comment at common.sh:1188-1189. Suggest: "lists with command ls so a user ls alias or function from the sourced ~/.bashrc cannot reorder or filter the snippets."
  2. Consider a follow-up for the unquoted-substitution splitting, noting that kit_spec_files is the control that currently makes it unreachable.

@wz-gsa
wz-gsa merged commit d7dbeb6 into main Oct 19, 2026
5 checks passed
@wz-gsa
wz-gsa deleted the fix/rc-bridge-command-ls branch October 19, 2026 19:23
mogul pushed a commit that referenced this pull request Oct 22, 2026
🤖 I have created a release *beep* *boop*
---


##
[4.1.0](v4.0.2...v4.1.0)
(2026-10-22)


### Features

* **kits:** pin agentic-coding-patterns v1.15.0
([#595](#595))
([1e9ef27](1e9ef27))
* **kits:** pin agentic-coding-patterns v1.16.1
([#609](#609))
([20d6bab](20d6bab))
* **opencode:** use generic devenv base by default
([#584](#584))
([cefd6f2](cefd6f2))


### Bug Fixes

* **ci:** bump markdown-it to 14.3.3 and smol-toml to 1.9.0 overrides
([#599](#599))
([5ab74b8](5ab74b8))
* **msb:** stop false "no ssh-agent route" warnings from grep sigpipe
([#598](#598))
([24c8493](24c8493))
* **provider-facts:** preserve caller-visible assignments through
wrapper subshell
([#603](#603))
([2361b11](2361b11))
* **provider-facts:** preserve unset caller IFS
([#605](#605))
([3fe3150](3fe3150))
* **rc.d:** list ~/.rc.d with command ls in the login bridge
([#588](#588))
([d7dbeb6](d7dbeb6))
* **verify:** make provider backend verification fail closed
([#602](#602))
([f67041a](f67041a))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] ~/.rc.d login bridge lists snippets through the user's ls alias or function

2 participants