Class: Pikuri::Workspace::Filesystem::AllowAll

Inherits:
Pikuri::Workspace::Filesystem show all
Defined in:
lib/pikuri/workspace/filesystem.rb

Overview

Unrestricted variant of Pikuri::Workspace::Filesystem: every path resolves, with one carve-out — paths under CREDENTIAL_DENYLIST (the user’s ~/.ssh, ~/.aws, ~/.gnupg, ~/.docker, ~/.kube, ~/.netrc, and /etc/shadow) still raise. Intended for dev-container / Docker mode where the container is the security boundary; the denylist remains as defense-in-depth against prompt-injection exfiltration of credentials that are commonly bind-mounted into a container from the host. Pairs naturally with --yolo (no Confirmer prompt) — but note that combining with Code::Bash::Sandbox::Bubblewrap defeats the sandbox (the whole filesystem ends up bind-mounted in), and bash inside the sandbox bypasses the denylist anyway, so the intended combo is ALLOW_ALL + Sandbox::NONE inside a container.

Project root, temp

project_root: is still accepted for parity with Pikuri::Workspace::Filesystem, even though it’s not a real containment ceiling under AllowAll. It is NOT validated against DENIED_PROJECT_ROOTS (passing ‘/’ is legitimate inside a container). It still serves as the base for relative-path resolution and the chdir target tools like Bash use. temp: behaves the same way as Pikuri::Workspace::Filesystem.

Denylist semantics

Each entry is realpath’d lazily at check time when it exists (so a symlink at e.g. /tmp/decoy → ~/.ssh/id_rsa still gets caught — the resolved path lands under ~/.ssh). Non-existent entries fall back to a literal-prefix match — blocks the agent from creating a credential dir the user doesn’t have yet (e.g. planting ~/.gnupg for a later GPG operation to pick up). The list is hardcoded; subclass for a host with a different policy.

Constant Summary collapse

CREDENTIAL_DENYLIST =

Credential locations that even ALLOW_ALL refuses. Expanded via ENV at class-load time and unioned with the /root variants (dev-container default user). Frozen.

begin
  homes = [ENV.fetch('HOME', nil), '/root'].compact.uniq
  per_home = %w[.ssh .aws .gnupg .docker .kube .netrc]
  user_paths = homes.flat_map { |h| per_home.map { |p| File.join(h, p) } }
  (user_paths + %w[/etc/shadow]).map { |p| Pathname.new(p) }.uniq.freeze
end

Constants inherited from Pikuri::Workspace::Filesystem

CACHE_BASE, DENIED_PROJECT_ROOTS, INTERNAL_TEMP_STALE_SECONDS

Instance Attribute Summary

Attributes inherited from Pikuri::Workspace::Filesystem

#alias_tmp_to_temp, #project_root, #readable, #temp, #writable

Instance Method Summary collapse

Methods inherited from Pikuri::Workspace::Filesystem

#env, #internal_temp, mint_internal_temp, sweep_stale_internal_temps!

Constructor Details

#initialize(project_root: Dir.pwd, temp: false, alias_tmp_to_temp: false, env: nil) ⇒ AllowAll

Returns a new instance of AllowAll.

Parameters:



482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/pikuri/workspace/filesystem.rb', line 482

def initialize(project_root: Dir.pwd, temp: false, alias_tmp_to_temp: false, env: nil)
  @project_root = Pathname.new(project_root).realpath

  @internal_temp = nil
  @temp = temp ? mint_playground : nil
  @alias_tmp_to_temp = alias_tmp_to_temp && !@temp.nil?
  @env_override = env

  # Advertise "everything is in scope" via the accessor surface so
  # callers that inspect +readable+/+writable+ (system-prompt
  # rendering, Bubblewrap bind-mount construction) see the
  # intended semantics. The actual containment is the denylist
  # in {#resolve_for_read}/{#resolve_for_write}.
  @writable = [Pathname.new('/').realpath, @temp].compact.uniq
  @readable = @writable.dup
end

Instance Method Details

#resolve_for_read(path) ⇒ Pathname

Parameters:

  • path (String)

Returns:

  • (Pathname)

Raises:



502
503
504
# File 'lib/pikuri/workspace/filesystem.rb', line 502

def resolve_for_read(path)
  resolve_unrestricted(path)
end

#resolve_for_write(path) ⇒ Pathname

Parameters:

  • path (String)

Returns:

  • (Pathname)

Raises:



509
510
511
# File 'lib/pikuri/workspace/filesystem.rb', line 509

def resolve_for_write(path)
  resolve_unrestricted(path)
end