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
34 changes: 13 additions & 21 deletions builtins/tests/help/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,31 +167,30 @@ func TestHelpColumnsAligned(t *testing.T) {

func TestHelpRestrictedShowsOnlyAllowed(t *testing.T) {
stdout, stderr, code := runScript(t, "help", "",
interp.AllowedCommands([]string{"rshell:echo"}))
interp.AllowedCommands([]string{"rshell:echo", "rshell:help"}))
assert.Equal(t, 0, code)
assert.Empty(t, stderr)
assert.Contains(t, stdout, "echo")
assert.Contains(t, stdout, "help") // help is always listed
assert.Contains(t, stdout, "help")
assert.NotContains(t, stdout, "cat")
assert.NotContains(t, stdout, "grep")
assert.NotContains(t, stdout, "ls")
}

func TestHelpRestrictedSingleCommand(t *testing.T) {
// Only "ls" is explicitly allowed; help should still appear.
stdout, _, code := runScript(t, "help", "",
interp.AllowedCommands([]string{"rshell:ls"}))
interp.AllowedCommands([]string{"rshell:ls", "rshell:help"}))
assert.Equal(t, 0, code)
assert.Contains(t, stdout, "help")
assert.Contains(t, stdout, "ls")
assert.NotContains(t, stdout, "echo")
}

func TestHelpRestrictedAlignmentAdjusts(t *testing.T) {
// With "wc" (2-char) and "strings" (7-char) plus implicit "help" (4-char),
// With "wc" (2-char), "strings" (7-char), and "help" (4-char),
// the column width should match the longest allowed name.
stdout, _, code := runScript(t, "help", "",
interp.AllowedCommands([]string{"rshell:wc", "rshell:strings"}))
interp.AllowedCommands([]string{"rshell:wc", "rshell:strings", "rshell:help"}))
assert.Equal(t, 0, code)

lines := strings.Split(strings.TrimSpace(stdout), "\n")
Expand All @@ -210,27 +209,20 @@ func TestHelpRestrictedAlignmentAdjusts(t *testing.T) {
}
}

func TestHelpAlwaysAvailable(t *testing.T) {
// help is not in the allowed list, but should still run.
stdout, stderr, code := runScript(t, "help", "",
func TestHelpNotAllowedWhenNotInList(t *testing.T) {
// help is not in the allowed list and should be blocked.
_, stderr, code := runScript(t, "help", "",
interp.AllowedCommands([]string{"rshell:echo", "rshell:ls"}))
assert.Equal(t, 0, code)
assert.Empty(t, stderr)
assert.Contains(t, stdout, "help")
assert.Contains(t, stdout, "echo")
assert.Contains(t, stdout, "ls")
assert.NotContains(t, stdout, "cat")
assert.Equal(t, 127, code)
assert.Contains(t, stderr, "command not allowed")
}

func TestHelpAlwaysAvailableNoCommands(t *testing.T) {
// Even with an empty allowed list, help should work.
stdout, stderr, code := runScript(t, "help", "",
_, stderr, code := runScript(t, "help", "",
interp.AllowedCommands([]string{}))
assert.Equal(t, 0, code)
assert.Empty(t, stderr)
// Only help itself should be listed.
assert.Contains(t, stdout, "help")
assert.NotContains(t, stdout, "echo")
assert.Equal(t, 127, code)
assert.Contains(t, stderr, "command not allowed")
}

// --- Error handling ---
Expand Down
10 changes: 4 additions & 6 deletions interp/runner_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ func (r *Runner) call(ctx context.Context, pos syntax.Pos, args []string) {
}
name := args[0]

// Check whether the command is allowed. "help" is always permitted so
// users can discover available commands regardless of the active policy.
if !r.allowAllCommands && name != "help" && !r.allowedCommands[name] {
if !r.allowAllCommands && !r.allowedCommands[name] {
r.errf("%s: command not allowed\n", name)
r.exit.code = 127
return
Expand All @@ -267,7 +265,7 @@ func (r *Runner) call(ctx context.Context, pos syntax.Pos, args []string) {
if fn, ok := builtins.Lookup(name); ok {
var runCmd func(context.Context, string, string, []string) (uint8, error)
runCmd = func(ctx context.Context, dir string, cmdName string, cmdArgs []string) (uint8, error) {
if !r.allowAllCommands && cmdName != "help" && !r.allowedCommands[cmdName] {
if !r.allowAllCommands && !r.allowedCommands[cmdName] {
return 127, fmt.Errorf("%s: command not allowed", cmdName)
}
cmdFn, ok := builtins.Lookup(cmdName)
Expand Down Expand Up @@ -324,7 +322,7 @@ func (r *Runner) call(ctx context.Context, pos syntax.Pos, args []string) {
return builtins.FileID{Dev: dev, Ino: ino}, true
},
CommandAllowed: func(n string) bool {
return r.allowAllCommands || n == "help" || r.allowedCommands[n]
return r.allowAllCommands || r.allowedCommands[n]
},
}
if r.stdin != nil {
Expand Down Expand Up @@ -386,7 +384,7 @@ func (r *Runner) call(ctx context.Context, pos syntax.Pos, args []string) {
return builtins.FileID{Dev: dev, Ino: ino}, true
},
CommandAllowed: func(cmdName string) bool {
return r.allowAllCommands || cmdName == "help" || r.allowedCommands[cmdName]
return r.allowAllCommands || r.allowedCommands[cmdName]
},
RunCommand: runCmd,
Proc: r.proc,
Expand Down
10 changes: 0 additions & 10 deletions tests/scenarios/cmd/help/always_available.yaml

This file was deleted.

4 changes: 2 additions & 2 deletions tests/scenarios/cmd/help/restricted_commands.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
description: Help lists only commands allowed by the active policy, plus itself.
description: Help lists only commands allowed by the active policy.
skip_assert_against_bash: true
input:
allowed_commands: ["rshell:echo"]
allowed_commands: ["rshell:echo", "rshell:help"]
script: |+
help
expect:
Expand Down
Loading