Skip to content

Latest commit

 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

oss-tooling

Tooling for the Schwarz Digits open-source compliance program.

This repository contains the command-line tools and GitHub Actions workflows that we use to maintain transparency, license compliance, and security hygiene across our open-source organizations on GitHub (SchwarzDigits, SchwarzIT).

Status

Early development. The first focus is a repository inventory tool that enumerates our open-source repositories and records their metadata, license status, and key compliance signals.

Components

Component Description
cmd/osstool Command-line entry point
internal/inventory Repository enumeration and metadata collection
internal/github GitHub API client (GraphQL-first)

More components will be added over time.

Usage

The tool is intended to run via GitHub Actions for production runs and locally for development. Local execution requires Go 1.23+ and a GitHub personal access token in GITHUB_TOKEN.

make build
export GITHUB_TOKEN=ghp_xxx

# Collect repositories using the orgs listed in config/inventory.yml
./bin/osstool inventory run

# Or override the config and pass orgs on the command line
./bin/osstool inventory run --orgs SchwarzDigits,SchwarzIT

# Generate a Markdown summary from the latest output
./bin/osstool inventory report

# Generate a report that also calls out what changed since a previous
# snapshot (file or directory of per-org JSON files):
./bin/osstool inventory report \
  --input ./output/latest \
  --diff-from ./output/2026-04-30 \
  --output ./output/summary.md

# Compare two snapshots directly and emit a Markdown diff
./bin/osstool inventory diff \
  --from ./output/2026-04-30 \
  --to ./output/latest \
  --output ./output/diff.md

Output layout:

output/
├── 2026-04-30/
│   ├── SchwarzDigits.json
│   └── SchwarzIT.json
└── latest/
    ├── SchwarzDigits.json
    └── SchwarzIT.json
output/summary.md   # produced by `inventory report`

The per-repo JSON schema includes a compliance_checks object (with secrets_vuln and license sub-objects, each carrying status, completed_at, and url) and a likely-owner hint (likely_owner, likely_owner_source). All optional fields use omitempty, so older snapshots that predate a field still parse cleanly; missing fields default to zero values.

Snapshots written by earlier versions of this tool used five flat last_compliance_run_* fields instead of compliance_checks. The diff command silently skips per-check transitions when one side of the comparison lacks compliance_checks — a one-time silent boundary on the upgrade.

Configuration

config/inventory.yml drives both which orgs are scanned and which repos are excluded:

orgs:
  - SchwarzDigits
  - SchwarzIT
excludes:
  - "*/.github"                      # any-org pattern
  - SchwarzDigits/oss-compliance     # exact org/name pattern

orgs are the default list scanned by osstool inventory run; the --orgs CLI flag overrides them. excludes lists repos that aren't meaningful subjects of compliance reporting (the central workflow definition, data-only repos, the org .github repo). Two pattern forms are supported: <org>/<name> for an exact match and */<name> to match a name across any org. Comparisons are case-sensitive.

Point at a different config with --config <path>. The CLI works without the file present — a missing config is logged and treated as "no defaults", in which case --orgs becomes mandatory.

Excluded repos are dropped at collection time, so they never appear in the per-org JSON snapshots or the report. Snapshots taken before a repo was added to the excludes will still contain it; the diff sub-command will surface the one-time disappearance as a "Repositories removed" entry.

Report sections

Every repo is classified into one of three lifecycle statuses — active (pushed in the last 12 months), stale (older), or archived — and that vocabulary is reused across the per-org table, the Compliance: Migration Priority section, and the Archive Candidates section. The report's Status definitions footer at the end of the report spells out the rules in one place; section methodology hints reference the footer rather than restating them.

Status header percentages use the active count as the denominator — stale and archived repos can't realistically be onboarded, so including them would understate adoption progress. The license-compliance bullet also surfaces the overall ratio (across all statuses), since legal obligation isn't excused by stale status.

The central Compliance workflow has three jobs: secret-and-vuln-scan, decide-ort, and license-and-sbom. Only the first and third are real compliance checks; decide-ort is a routing job that decides whether ORT (the license analyzer) needs to run for the current trigger. Because ORT skips on doc-only pushes, reading just the workflow's top-level conclusion would report green when no license analysis happened — masking real violations. The inventory therefore tracks each check's most recent meaningful run independently (skipping conclusion: skipped) and surfaces them in separate columns of the Compliance status table.

A check shows – never when no meaningful run has occurred within the lookback window — distinct from ❌ failure. The lookback uses two phases: first the latest 30 runs of the Compliance workflow unfiltered, then (for the license check only, if still empty) one fallback to the most recent event=schedule run. The cron is the floor on freshness because it forces a full ORT execution every Sunday. For newly-onboarded repos – never is normal until the schedule fires. If a long-running repo shows – never for license, it means the cron itself is broken or decide-ort is failing on the scheduled trigger — investigate the workflow configuration.

Note on terminology: the License compliance bullet in the status header tracks presence of a LICENSE file in each repo (static metadata). The Latest license checks bullet and the License (ORT) column in the compliance table track ORT runtime analysis of dependency licenses (per-run signal). They share the word "license" but answer different questions; both are surfaced because both are required for compliance.

The "Likely owner" column attributes a repo first to a CODEOWNERS file (suffix (CO)) and otherwise to the dominant non-bot author in the last 100 commits on the default branch, with a fallback to commits 101-200 if the first 100 are bot-only (suffix (committer)). The underlying LikelyOwnerSource field on the JSON snapshot is one of codeowners, top_committer_recent, or empty (renaming the older top_committer_90d value — readers handling old snapshots can treat any top_committer_* value as the same source class).

Make targets

Target Description
make build Build the binary at ./bin/osstool
make test Run the Go test suite
make vet Run go vet ./...
make lint Run golangci-lint run (requires golangci-lint installed locally)
make run-inventory Convenience wrapper around inventory run with default orgs
make clean Remove bin/ and output/

Contributing

Contributions are welcome. Please see CONTRIBUTING.md in our .github repository for general guidelines, including our Contributor License Agreement.

License

Apache License 2.0. See LICENSE.

About

Tooling for the Schwarz Digits open-source compliance program

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages