No description
  • Scheme 72.2%
  • Shell 18.9%
  • Makefile 6.8%
  • C 1.8%
  • Common Lisp 0.3%
Find a file
2026-07-30 15:46:43 -06:00
.builds ci: set umask 022 in package/verify tasks too (jerbuild creates group-writable cache dirs during pkg operations) 2026-07-22 13:10:56 -06:00
.jerboa Resolve security audit findings 2026-07-11 17:22:32 -06:00
docs Resolve security audit findings 2026-07-11 17:22:32 -06:00
lib/jgl fix(client): guard JSON decode of 2xx response bodies 2026-07-22 13:24:06 -06:00
scripts Resolve security audit findings 2026-07-11 17:22:32 -06:00
support Resolve security audit findings 2026-07-11 17:22:32 -06:00
test fix: ASCII-only pct-encode, path validation, request cleanup 2026-07-21 10:47:29 -06:00
.gitignore jpkg: complete binary package setup 2026-07-30 15:09:43 -06:00
.jerbuild Resolve security audit findings 2026-07-11 17:22:32 -06:00
AGENTS.md docs: remove jerboa-emacs restriction 2026-07-30 15:46:43 -06:00
build-all.ss Initial jgl: Jerboa GitLab CLI (issues + CI/CD) 2026-06-01 13:19:02 -06:00
build-jgl-cross.ss Resolve security audit findings 2026-07-11 17:22:32 -06:00
jgl.ss Security hardening and release readiness 2026-06-23 10:49:55 -06:00
jpkg.lock jpkg: complete binary package setup 2026-07-30 15:09:43 -06:00
jpkg.policy.sexp jpkg: complete binary package setup 2026-07-30 15:09:43 -06:00
jpkg.sexp jpkg: complete binary package setup 2026-07-30 15:09:43 -06:00
LICENSE Switch to MIT license 2026-07-21 13:42:17 -06:00
Makefile build: add lint target 2026-07-21 11:56:17 -06:00
README.md Resolve security audit findings 2026-07-11 17:22:32 -06:00
SECURITY.md Resolve security audit findings 2026-07-11 17:22:32 -06:00

jerboa-gitlab — jgl

A small GitLab CLI written in Jerboa: fetch issues, query CI/CD, and archive issues to markdown. It talks to the GitLab REST API v4 over HTTPS (Rustls, via the bundled jerboa-native crate).

Inspired by gitlab-issue-exporter (a Go issue-archiver); jgl keeps the markdown-export idea and adds CI/CD queries and a JSON output mode.

What it does

  • Issues — list (with state/label/search filters), show one issue with its comments, and export every issue to one markdown file per issue.
  • CI/CD — list recent pipelines, show a pipeline and its jobs, list recent jobs, and report the latest pipeline status for a ref.
  • Project — show project metadata (a quick auth/connectivity check).
  • Output — human-readable text (default) or raw JSON (--format json).

Build

jgl builds with just jerbuild — it bundles Chez Scheme, the Jerboa stdlib, and the jerboa-native Rust crate (Rustls HTTPS). You need jerbuild, a C compiler, and cargo.

make binary       # -> ./jgl
make install      # -> ~/.local/bin/jgl
make test         # run the unit tests
make release-evidence

The same make binary works natively on macOS, Linux, and FreeBSD. To cross-compile from macOS to other targets, see Cross-compilation.

Usage

jgl <command> [options]
Command Description
project Show project info (verifies url/token/project)
issues List issues
issue <iid> Show one issue with comments
export Export all issues to markdown (--output DIR)
pipelines List recent CI/CD pipelines
pipeline <id> Show a pipeline and its jobs
jobs List recent jobs (--pipeline ID to scope)
ci-status Latest pipeline status (--ref to scope)
Option Description
--url URL GitLab base URL (env GITLAB_URL, default https://gitlab.com)
--token-fd FD Read an access token from a dedicated descriptor (GITLAB_TOKEN also supported)
--trusted-origin O Required exact trust assertion for authenticated custom GitLab origins
--allow-insecure-loopback Permit HTTP only for literal 127.0.0.1 development
-p, --project P Project ID or path, e.g. 123 or group/proj (env GITLAB_PROJECT)
-f, --format FMT text (default) or json
--state STATE issues: opened | closed | all (default all)
--labels A,B issues: filter by labels
--search TEXT issues: search term
--ref REF pipelines/ci-status: branch or tag
--status STATUS pipelines: filter by status
--pipeline ID jobs: restrict to a pipeline
-o, --output DIR export: output directory (default ./issues)
--config PATH Config file (default ~/.gitlab.yaml; also GITLAB_CONFIG)
-h, --help Show help
--version Show version

A token with read_api scope is needed for private projects; public projects read without one.

Security

jgl can read private GitLab project metadata, issues, comments, CI status, and attachments. Prefer a read_api token; token arguments are rejected, so use a secret-manager environment injection, a dedicated descriptor, or an owner-only config. Treat jgl export output as sensitive. Credential and export handling are documented in docs/credential-handling.md. Native dependency provenance is documented in docs/dependency-provenance.md, and local release evidence is documented in docs/release-evidence.md.

Configuration

jgl resolves each setting with the precedence flag environment ~/.gitlab.yaml default. Use whichever fits:

export GITLAB_URL="https://gitlab.com"
export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"
export GITLAB_PROJECT="group/project"

or a flat ~/.gitlab.yaml (override the path with --config or GITLAB_CONFIG):

url: https://gitlab.com
token: glpat-xxxxxxxxxxxx
project: group/project
format: text

An existing config must be a canonical, non-symlink, owner-only regular file (normally mode 0600). Authenticated custom instances must also set an exact trusted_origin, for example https://gitlab.example:443. URLs use HTTPS; plaintext HTTP is available only with --allow-insecure-loopback for literal 127.0.0.1 development.

Examples

# Issues (filters, JSON)
jgl issues -p group/proj --state opened --labels bug
jgl issue 42 -p group/proj
jgl issues -p group/proj -f json

# CI/CD
jgl pipelines -p group/proj --ref main
jgl pipeline 123456 -p group/proj
jgl ci-status -p group/proj --ref main

# Archive every issue to markdown
jgl export -p group/proj -o ./archive

Markdown export

jgl export writes one directory per issue:

issues/
├── issue-1/
│   ├── README.md
│   └── attachments/        (referenced /uploads/ files, best-effort)
└── issue-2/
    └── README.md

Each README.md has the title, metadata (state, author, assignees, labels, dates, URL), the description, and non-system comments. When the project is given as a path (group/proj), referenced /uploads/ attachments are downloaded into attachments/ and the links are rewritten to point at the local copies; if a download fails the original link is left intact. Issue directory names and attachment filenames derived from API responses are sanitized before local filesystem writes. Export directories are descriptor-walked without following symlinks, created mode 0700, and files are created exclusively at mode 0600; an existing destination is never overwritten. Human-readable terminal output escapes control/bidirectional characters. JSON and markdown exports remain lossless representations of the project content.

Cross-compilation

make binary is portable — it runs natively on macOS, Linux, and FreeBSD. To build a Linux x86_64 binary from macOS:

make cross-linux      # -> jgl-linux-amd64  (static musl ELF)

jgl's HTTPS uses rustls (the jerboa-native crate), so this cross-builds that crate for x86_64-unknown-linux-musl and static-links it — the same TLS backend as the native build (not the OpenSSL shim some older jerboa-* cross scripts use). It needs:

  • a full Chez scheme compiler — the Makefile falls back to $JERBOA_HOME/build/chez/tarm64osx/bin/tarm64osx/scheme if none is on PATH;
  • the cross-built Chez + xpatch under $JERBOA_HOME (.chez-cross-ta6le, build/chez/xc-ta6le/s/xpatch);
  • x86_64-linux-musl-gcc;
  • a rustup toolchain with the musl target (rustup target add x86_64-unknown-linux-musl).

Override JERBOA_HOME, SCHEME, RUSTUP_TC, or MUSL_CC on the make line as needed; see build-jgl-cross.ss for the details. (A FreeBSD cross would follow the same shape with the x86_64-unknown-freebsd Rust target + a sysroot; not wired up yet.)

Layout

jgl.ss                     entry point (argv via env or command line)
lib/jgl/client.ss          HTTPS + JSON + pagination + percent-encoding
lib/jgl/config.ss          resolve url/token/project from flags + env
lib/jgl/secure-fs.ss       owner/mode checks + descriptor-relative exports
lib/jgl/format.ss          field access, JSON re-serialization, formatters
lib/jgl/issues.ss          issue list/get/notes + markdown export
lib/jgl/ci.ss              pipelines / jobs / latest status
lib/jgl/cli.ss             argument parsing, dispatch, rendering
test/test-jgl.ss           policy/format/path unit tests
test/test-secure-fs.ss     no-follow/private/exclusive filesystem tests

License

Apache-2.0.