Skip to content
Closed
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
103 changes: 103 additions & 0 deletions AI_DISCLOSURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
tools-used:
- OpenCode
models-used:
- claude-opus-4-8
- claude-sonnet-4-6
- claude-sonnet-5
- gpt-5.6-sol
providers:
- Anthropic
- OpenAI
scope:
human-authored: >
Repository policy and governance text, and final human review of
all merged changes.
ai-generated: >
Shell wrapper scripts (bin/, lib/), the `azoidcapp` Python helper,
documentation (docs/), and CI/lint configuration — all with human
review and validation.
last-updated: 2026-07-18
---

# AI Disclosure

This file describes how AI tools are used in this repository.

## Disclosure levels

This repository uses the vocabulary defined by the
[W3C AI Content Disclosure Community Group](https://www.w3.org/community/ai-content-disclosure/)
(a community-group effort, not a ratified W3C standard).
Four levels are defined:

| Level | Meaning |
| --- | --- |
| `none` | No AI tools were used. |
| `ai-assisted` | AI contributed, but a human authored and reviewed. |
| `ai-generated` | AI generated the content; a human reviewed it. |
| `autonomous` | AI produced the content without human review. |

Per the community group's "absence = unknown" principle, files
without an explicit disclosure tag do not imply a specific level.

## Scope of AI use in this repository

**Repository policy and governance text** — including this disclosure
file — is human-authored. The final text is authored and validated by
human contributors.

**Source code in this repository is largely AI-generated:** AI tools
produce the initial implementation of the sandboxed AI CLI wrapper
scripts (`bin/bwopencode`, `bin/bwcodex`, `bin/bwclaude`,
`bin/bwcopilot`) and the shared `lib/bwrap_sandbox_lib.sh` sandbox
library, as well as `bin/gh-protect-branch`, `bin/azoidcapp`,
`bin/pemdecompose`, `lib/gpg-passwd.sh`, associated documentation, and
CI/lint configuration. A human contributor reviews, tests, and
validates all content before merging; the human remains accountable
for every merged change.

## Tools and models

AI assistance in this repository is provided via
**OpenCode** using Anthropic models for implementation and OpenAI GPT-5.6-sol
for critical code review. See the metadata block at the top of this file for
the current list of models.

Per-commit attribution uses the `Assisted-by: AGENT:MODEL` trailer
format. Those per-commit trailers are the authoritative record of
which model contributed to a specific change.

## Purpose of use

AI tools are used to:

- Draft and refactor the bubblewrap-sandboxed AI CLI wrapper scripts
(`bwopencode`, `bwcodex`, `bwclaude`, `bwcopilot`) and the shared
`bwrap_sandbox_lib.sh` library.
- Draft and refactor `gh-protect-branch`, `azoidcapp`, `pemdecompose`,
and `gpg-passwd.sh`.
- Perform critical code review (GPT-5.6-sol).
- Generate commit messages, code review responses, and documentation.

## Input data / datasets

Only repository source files, public documentation, and
non-sensitive prompts are provided as input to AI models.

## Limitations and known biases

- LLM output may contain errors, hallucinations, or bias
inherited from training data.
- All AI-generated content is independently reviewed and validated
by a human contributor before it is merged.
- The models listed above do not have access to internal BNL
systems, live data, or non-public information unless explicitly
provided in a prompt.

## Reviewer disclaimer

AI-generated content in this repository has been reviewed.
Inclusion of AI-generated material does not substitute for human
accountability: the contributing staff member is responsible for the
correctness and appropriateness of every merged change.
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ docs/ Per-script and per-library documentation
| `bwcodex` | OpenAI Codex CLI in a bubblewrap sandbox | [docs/bw-wrappers.md](docs/bw-wrappers.md) |
| `bwcopilot` | GitHub Copilot CLI in a bubblewrap sandbox | [docs/bw-wrappers.md](docs/bw-wrappers.md) |
| `bwopencode` | OpenCode in a bubblewrap sandbox | [docs/bw-wrappers.md](docs/bw-wrappers.md) |
| `gh-protect-branch` | Apply NSLS-II standard branch protection to a GitHub repo (all branches); enables secret scanning and push protection | [docs/gh-protect-branch.md](docs/gh-protect-branch.md) |
| `gh-protect-branch` | Apply NSLS-II standard branch protection to a GitHub repo (all branches); enables secret scanning and push protection; optionally restricts branch creation to named patterns | [docs/gh-protect-branch.md](docs/gh-protect-branch.md) |
| `pemdecompose` | List and verify certificates in a PEM file | [docs/pemdecompose.md](docs/pemdecompose.md) |

All `bw*` wrappers share `lib/bwrap_sandbox_lib.sh` for sandbox construction.
Expand Down Expand Up @@ -99,6 +99,42 @@ Common wrapper options:
`bwclaude` also supports `--debug`. See each script's `--help` for the
authoritative option list.

### `gh-protect-branch`

Apply NSLS-II standard branch protection to a GitHub repository. Enforces
PR reviews, signed commits, deletion and force-push blocking, and secret
scanning via a repository ruleset and a named-branch classic protection
rule. Optionally restricts who can create new branches.

```text
gh-protect-branch [--approvers <team-slug>] [--no-sign-commits]
[--restrict-branch-creation [--exclude-branches <csv>]]
<owner/repo> [branch]
gh-protect-branch --only-restrict-creation [--exclude-branches <csv>]
<owner/repo>
```

| Option | Effect |
| --- | --- |
| `--approvers <team-slug>` | Restrict stale-review dismissal to this team (team must exist in the org) |
| `--no-sign-commits` | Do not require signed commits |
| `--restrict-branch-creation` | Also apply a creation-restriction ruleset (additive) |
| `--only-restrict-creation` | Apply only the creation-restriction ruleset; skip full protection |
| `--exclude-branches <csv>` | Comma-separated fnmatch patterns allowed to be created (default: `main,preview`); requires `--restrict-branch-creation` or `--only-restrict-creation` |
| `<owner/repo>` | Repository in `owner/repo` format (required) |
| `[branch]` | Named branch for classic protection (default: `main`) |
| `-h`, `--help` | Show help and exit |

```bash
gh-protect-branch NSLS2/n2sndocs
gh-protect-branch --approvers n2sn-admins NSLS2/n2sndocs main
gh-protect-branch --only-restrict-creation \
--exclude-branches main,preview NSLS2/n2sndocs
```

Exit codes: `0` success, `1` usage error or missing dependency,
`2` `gh` not authenticated, non-zero `gh` exit code on API failure.

### `gpg-passwd.sh`

Source the library and call `decrypt_env_file`:
Expand Down Expand Up @@ -194,3 +230,8 @@ Requires only `openssl`.

See the per-script doc pages under [`docs/`](docs/) for full usage,
options, and caveats.

## AI disclosure

This repository's contents are largely AI-generated with human
review. See [`AI_DISCLOSURE.md`](AI_DISCLOSURE.md) for details.
2 changes: 1 addition & 1 deletion bin/bwclaude
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ parse_wrapper_args() {
# not depend on PATH lookup inside the sandbox.
# Sets globals: _TOOL_BIN, _TOOL_CMD
resolve_tool_binary() {
_TOOL_BIN="$(command -v claude 2> /dev/null || true)"
_TOOL_BIN="$(resolve_real_tool_binary claude)"
if [[ -z "${_TOOL_BIN}" ]]; then
echo "Error: 'claude' not found in PATH." >&2
exit 1
Expand Down
2 changes: 1 addition & 1 deletion bin/bwcodex
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ parse_wrapper_args() {
# not depend on PATH lookup inside the sandbox.
# Sets globals: _TOOL_BIN, _TOOL_CMD
resolve_tool_binary() {
_TOOL_BIN="$(command -v codex 2> /dev/null || true)"
_TOOL_BIN="$(resolve_real_tool_binary codex)"
if [[ -z "${_TOOL_BIN}" ]]; then
echo "Error: 'codex' not found in PATH." >&2
exit 1
Expand Down
2 changes: 1 addition & 1 deletion bin/bwcopilot
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ parse_wrapper_args() {
# archived/deprecated as of Oct 2025.
# Sets globals: _TOOL_BIN, _TOOL_CMD
resolve_tool_binary() {
_TOOL_BIN="$(command -v copilot 2> /dev/null || true)"
_TOOL_BIN="$(resolve_real_tool_binary copilot)"
if [[ -z "${_TOOL_BIN}" ]]; then
echo "Error: 'copilot' not found in PATH." >&2
echo "Install the standalone GitHub Copilot CLI from https://github.com/github/copilot-cli" >&2
Expand Down
32 changes: 31 additions & 1 deletion bin/bwopencode
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ source "${SCRIPT_DIR}/../lib/bwrap_sandbox_lib.sh"
# ═══════════════════════════════════════════════════════════════════

INIT_AUTH=0
FORWARD_GH_TOKENS=0
OC_CONFIG_BINDS=()

# ═══════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -101,6 +102,10 @@ parse_wrapper_args() {
INIT_AUTH=1
shift
;;
--github-tokens)
FORWARD_GH_TOKENS=1
shift
;;
--new-session)
# shellcheck disable=SC2034 # consumed by sourced bwrap_sandbox_lib.sh (sandboxed_exec)
FORCE_NEW_SESSION=1
Expand Down Expand Up @@ -135,7 +140,7 @@ parse_wrapper_args() {
# not depend on PATH lookup inside the sandbox.
# Sets globals: _TOOL_BIN, _TOOL_CMD
resolve_tool_binary() {
_TOOL_BIN="$(command -v opencode 2> /dev/null || true)"
_TOOL_BIN="$(resolve_real_tool_binary opencode)"
if [[ -z "${_TOOL_BIN}" ]]; then
echo "Error: 'opencode' not found in PATH." >&2
exit 1
Expand Down Expand Up @@ -179,6 +184,11 @@ Wrapper options (consumed before opencode sees the command line):
Symlinks are resolved before the safety check is applied.
--rw-path PATH Mount PATH (file or directory) read-write into the sandbox.
Same blocked-path rules as --ro-path. May be repeated.
--github-tokens Forward any GH_TOKEN_* environment variables into the
sandbox so the agent can authenticate the gh(1) CLI.
Off by default. When set, use per-command token selection:
GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo
GH_TOKEN="$GH_TOKEN_PERSONAL" gh issue list -R user/repo

All other arguments are passed through to opencode unchanged.

Expand Down Expand Up @@ -366,6 +376,9 @@ build_opencode_cache_mount() {
# ── OpenCode env vars ────────────────────────────────────────────
# Pass through any OPENCODE_* env vars (config overrides, etc.)
# Also pass through AIFAPIM_* env vars for NSLS-II Hermes gateway.
# With --github-tokens, also forward GH_TOKEN_* vars so the agent
# can authenticate gh(1) via per-command:
# GH_TOKEN="$GH_TOKEN_NSLS2" gh <subcommand>
build_opencode_env() {
# AIFAPIM gateway config
pass_through_if_set AIFAPIM_HOST
Expand All @@ -377,6 +390,23 @@ build_opencode_env() {
BWRAP_ARGS+=(--setenv "${_key}" "${!_key}")
fi
done < <(compgen -e)

# GitHub CLI token passthrough (opt-in via --github-tokens)
# In --dry-run mode the value is replaced with REDACTED so that tokens
# are not printed to the terminal in the bwrap command output.
if [[ "${FORWARD_GH_TOKENS}" -eq 1 ]]; then
local _gh_val
while IFS= read -r _key; do
if [[ "${_key}" == GH_TOKEN_* ]]; then
if [[ "${DRY_RUN}" -eq 1 ]]; then
_gh_val="REDACTED"
else
_gh_val="${!_key}"
fi
BWRAP_ARGS+=(--setenv "${_key}" "${_gh_val}")
fi
done < <(compgen -e)
fi
}

# ═══════════════════════════════════════════════════════════════════
Expand Down
Loading