Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

inclusive-language Administrator & Developer Guide

Generated April 2026 from cisco-open/inclusive-language at 0486454

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Architecture, configuration, and developer reference for cisco-open/inclusive-language. The repository is a small collection of rule files and helper scripts that drive third-party linters; it is not an executable on its own. This guide covers what each artifact does, how to deploy them across an organization, and how to extend or modify them.

The User Guide explains how to scan files. This guide explains how to operate the tooling at scale, run security and capacity reviews on it, and contribute new rules or scripts.


1. Architecture Overview

inclusive-language is a 17-file, single-folder repository (small complexity tier, 10,963 source characters total). Every file lives at the project root — there are no subdirectories. The repository ships three independent components that share only a name and a goal:

                              ┌────────────────────────┐
   project source tree   ────►│ alex (Node, npm)       │  prose linter
   (Markdown, code, docs)     │ + alex-race-rules.yaml │  warnings/CI gate
                              │ + .alexrc.js           │
                              │ + .alexignore          │
                              └────────────────────────┘

                              ┌────────────────────────┐
   project source tree   ────►│ woke (Go binary)       │  source-code linter
   (any text, any line)       │ + cisco-rules.yaml     │  warnings/CI gate
                              └────────────────────────┘

                              ┌────────────────────────┐
   GitHub org (any repo) ────►│ gh_search.py           │  CSV findings to
                              │ gh_default_branch.py   │  stdout + log file
                              │ + config.py            │
                              └────────────────────────┘
                                       ▲
                                       │
                              ┌────────────────────────┐
                              │  github.com REST API   │
                              │  (or Enterprise URL)   │
                              └────────────────────────┘

Note

The three components are completely decoupled. You can adopt the alex rule pack without ever touching woke, run the Python helpers without installing alex or woke, or use only cisco-rules.yaml against a fresh woke install. The repository is structured as an "à la carte" inclusive-language toolkit, not a unified product.

1.1 Component inventory

Component Path Role
alex rule pack alex-race-rules.yaml 13 term-pair entries consumed by alex
alex runtime config .alexrc.js allow list + noBinary: true flag
alex ignore list .alexignore gitignore-syntax path exclusions
woke rule pack cisco-rules.yaml 4 rule entries consumed by woke
GitHub keyword search gh_search.py PyGitHub-based code search (Enterprise)
Default-branch audit gh_default_branch.py Lists repos with master default branch
Helper script config template exampleconfig.py Sample of config.py for the helpers
Python dependency manifests Pipfile, requirements.txt Pin pygithub, requests, cffi, etc.
Node dependency manifest package.json Pins alex@^11.0.1, defines lint-language script
Project metadata LICENSE, NOTICE, CODE_OF_CONDUCT.md, SECURITY.md, README.md, bash-script-inventory.md Standard OSS hygiene files

1.2 Technology stack

Layer Technology Version pin
Prose linter alex ^11.0.1 (npm)
Source-code linter woke unpinned (binary, install latest)
Helper scripting language Python 3.9.6 (Pipfile)
GitHub API client PyGitHub 1.59.0
Network stack requests 2.31.0
TLS certifi 2023.7.22
C extension shim cffi + pycparser 1.15.1 / 2.21
Crypto pynacl, pyjwt 1.5.0 / 2.8.0
Deprecation handling deprecated, wrapt 1.2.14 / 1.15.0
Encoding charset-normalizer, idna, urllib3 3.2.0 / 3.4 / 2.0.4

1.3 Data flow

The three components have three distinct flows:

alex flow:
  developer types `npx alex .`
    └─► alex resolves `.alexrc.js` from CWD
          └─► alex reads `.alexignore` for excluded paths
                └─► alex walks remaining files, applies built-in
                    retext-equality rules + `alex-race-rules.yaml`
                      └─► writes warnings to stdout, exits 0 or 1

woke flow:
  developer types `woke --rule-in cisco-rules.yaml .`
    └─► woke loads its default rules + cisco-rules.yaml (merged by name)
          └─► woke walks files, scans every line
                └─► writes findings to stdout, exits 0 or 1

helper-script flow:
  developer types `python gh_search.py`
    └─► script imports config.py for token/endpoint/orgname
          └─► constructs Github(token) client (PyGitHub)
                └─► reads rate limit, sleeps if exhausted
                      └─► issues `search_code` query: "<keyword>" org:<org>
                            └─► iterates results (with 2s sleep), prints CSV lines
                                  └─► tee'd to log file via stdlib logging

Note

All flows are stateless. None of the three components persists data between runs. The Python helpers' rate-limit awareness lives entirely in the live Github client object — once the script exits, the rate-limit bookkeeping is forgotten and the next run starts fresh.


2. System Requirements

2.1 Per-component requirements

Component OS Runtime RAM Network
alex Linux, macOS, Windows Node.js 18+ 256 MB none after install
woke Linux, macOS, Windows Go binary (no runtime) 128 MB none
gh_*.py helpers Linux, macOS, Windows Python 3.9.6 (per Pipfile) 256 MB HTTPS to GitHub API

2.2 Network reachability for the helper scripts

The Python helpers issue HTTPS requests to one of:

  • https://api.github.com/ — public GitHub
  • A self-hosted enterprise URL such as https://github.example.com/api/v3/

Both flow through pygithub → requests → urllib3. Air-gapped environments that only proxy GitHub Enterprise traffic must whitelist (sorry — allowlist) the configured endpoint and provide outbound HTTPS on port 443.

2.3 Authentication

Component Auth required? Mechanism
alex No Operates on local files
woke No Operates on local files
gh_search.py Yes GitHub PAT, read scope sufficient
gh_default_branch.py Yes GitHub PAT, read scope sufficient

2.4 Disk

The repository itself is < 1 MB on disk after a fresh clone. After pip install -r requirements.txt and npm install, expect:

  • Python venv: ~25 MB (pygithub + dependencies)
  • Node node_modules/: ~12 MB (alex + retext-equality + dependencies)
  • woke binary: ~11 MB (single Go binary)

3. Configuration Reference

Every setting that any of the three components supports.

3.1 .alexrc.js — alex runtime configuration

Located at the project root. CommonJS export.

Key Type Default Description
allow string[] [] Rule IDs to skip globally. Cisco ships ["cisco-rules"] as a placeholder.
noBinary boolean false When true, suppresses warnings about gendered binary pairs (he/she, him/her). Cisco ships true.

Other keys alex supports (not used by Cisco's shipped config) include profanitySublevel (number, 0/1/2 — strictness of the profanity rule), reset (boolean — start from no enabled rules), and deny (string[] — force a rule on regardless of defaults). These appear in the upstream alex documentation.

3.2 .alexignore — alex path exclusions

Plain-text gitignore-style patterns. One pattern per line. # for comments. Matched relative to the directory containing .alexignore.

3.3 alex-race-rules.yaml — full term-pair reference

The complete shipped mapping (13 entries):

Inconsiderate Considerate alternatives Note
master primary, lead, hub, reference Avoid using the term master; these suggestions are for the computer term
masters primaries, hubs, references Avoid using the term master; these suggestions are for the computer term
slave secondary, worker, replica, node Avoid using the term slave; these suggestions are for the computer term
slaves secondaries, workers, replicas, nodes Avoid using the term slave; these suggestions are for the computer term
blackhat unethical hacker, malicious actor (no note)
whitehat ethical hacker, security researcher (no note)
nonwhite, non white person of color, people of color (no note)
blacklist, black list blocklist, wronglist, banlist, deny list Replace racially-charged language
blacklisted blocklisted, wronglisted, banlisted, deny-listed Replace racially-charged language
blacklisting blocklisting, wronglisting, banlisting, deny-listing Replace racially-charged language
whitelist, white list passlist, alrightlist, safelist, allow list Replace racially-charged language
whitelisted passlisted, alrightlisted, safelisted, allow-listed Replace racially-charged language
whitelisting passlisting, alrightlisting, safelisting, allow-listing Replace racially-charged language

Schema constraints:

  • Every entry must declare type: basic (the only type Cisco ships).
  • inconsiderate and considerate are required; both must be lists, even if a single value.
  • note is optional free text. When present, alex includes it in the warning output.

3.4 cisco-rules.yaml — full woke rule reference

The four shipped rules:

name terms alternatives
whitelist whitelist permit(list), allow(list)
blacklist blacklist ban(list), block(list)
master master primary, control, active, source, parent, main
slave slave secondary, subordinate, data, standby, subsidiary, replica, worker, child, helper, follower

Schema constraints (from woke's documentation):

  • Top-level key is rules: (a list).
  • Each rule has name (string), terms (list of strings), alternatives (list of strings).
  • woke supports an optional severity (error | warning | info) and an optional note per rule. Cisco's shipped file uses neither — every rule defaults to woke's default severity (warning).

3.5 package.json — Node dependency

{
  "devDependencies": {
    "alex": "^11.0.1"
  },
  "scripts": {
    "lint-language": "alex"
  }
}
Key Value Purpose
devDependencies.alex ^11.0.1 The only npm dep. ^ allows 11.x but not 12.0.
scripts.lint-language alex npm run lint-language invokes node_modules/.bin/alex.

3.6 Pipfile / requirements.txt — Python dependencies

The Pipfile is authoritative; requirements.txt is the autogenerated sibling (per the comment header). Both pin the same versions:

Package Version Used for
pygithub 1.59.0 GitHub API client
requests 2.31.0 HTTP transport
urllib3 2.0.4 HTTP/connection pool
certifi 2023.7.22 TLS root certs
idna 3.4 Internationalized domain names
charset-normalizer 3.2.0 Encoding detection
cffi 1.15.1 C bindings (transitive)
pycparser 2.21 cffi parser
pynacl 1.5.0 NaCl crypto bindings
pyjwt 2.8.0 JWT token handling
deprecated 1.2.14 Deprecation decorator
wrapt 1.15.0 Function-wrapping helper

Python version: python_version = "3.9.6". Newer Python releases work but are not the tested target.

Important

The requirements.txt file uses = instead of == (e.g., cffi = "==1.15.1"). This is the Pipfile-style syntax left in by the autogeneration step — pip itself accepts ==1.15.1 (note the doubled =) in regular requirements files. If you copy the file into a different tooling chain, normalize the assignment operator before piping it to pip install -r.

3.7 config.py — helper-script credentials

Constant Type Read by Required?
gh_api_key str gh_default_branch.py, gh_search.py Yes
gh_api_endpoint str gh_search.py (Enterprise mode) Required when running Enterprise mode
gh_orgname str gh_default_branch.py, gh_search.py Yes

Loaded via import config. Both scripts read config.gh_api_key at module import time; if config.py is absent or any of the constants is missing, the scripts fail with ImportError or AttributeError immediately at startup.


4. Deployment & Scaling

4.1 Single-repo deployment (most common)

Drop the four alex artifacts into the repo's root, install alex as a dev-dependency, wire up CI:

cp /path/to/inclusive-language/.alexrc.js .
cp /path/to/inclusive-language/.alexignore .
cp /path/to/inclusive-language/alex-race-rules.yaml .
cp /path/to/inclusive-language/package.json .   # or merge with existing
npm install

For woke, copy cisco-rules.yaml into a .woke/ subdirectory and reference it in CI:

mkdir -p .woke
cp /path/to/inclusive-language/cisco-rules.yaml .woke/

4.2 Multi-repo deployment (org-wide rollout)

Two patterns work well at scale.

Pattern A — Vendor the rules into every repo. Each repo carries its own copy of the YAML rule files. Updates propagate via a script that opens PRs across all repos. Pros: each repo is self-contained; no runtime dependency on a central service. Cons: rule changes require N PRs.

Pattern B — Centralized rule pack on a CDN or shared registry. Publish the YAML files to a known URL (internal artifact server, GitHub Pages, S3) and have CI pipelines fetch them at runtime:

- name: Fetch Cisco inclusive rules
  run: curl -sSfL https://internal.example.com/inclusive/alex-race-rules.yaml -o alex-race-rules.yaml
- name: Run alex
  run: npx alex .

Pros: one place to change rules. Cons: CI fails open if the CDN goes down; auditing what rules ran for a historical CI build is harder.

Tip

For most orgs, Pattern A is the right answer. Run a single gh search ... | xargs -I {} gh pr create ... script monthly to update any drifted copies, and gate every PR on the same CI workflow that runs alex.

4.3 GitHub Actions deployment template

Reusable workflow with both linters:

name: Inclusive Language
on:
  pull_request:
    branches: [main]

jobs:
  alex:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx alex .

  woke:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install woke
        run: |
          curl -sSfL https://git.io/getwoke | bash -s -- -b /usr/local/bin
      - name: Run woke
        run: woke --rule-in .woke/cisco-rules.yaml .

4.4 Scaling the GitHub helper scripts

The helper scripts are intentionally synchronous and rate-limit-aware. They do not parallelize. For large orgs (1000+ repos), you have three knobs:

  1. Increase rate limits. Authenticated GitHub search is 30 requests/minute. A GitHub App with installation-level auth bumps this; rewrite the helper to use a JWT-based App auth flow if you need more throughput.
  2. Shard by repo prefix. Run gh_default_branch.py against multiple filterkey inputs in parallel terminals — each call only iterates repos whose full_name matches the filter substring.
  3. Replace with a bulk clone + woke pass. For exhaustive coverage, clone every repo overnight and run woke locally; one woke invocation can scan thousands of repos in minutes once the local checkout exists.

Warning

The shipped helper scripts run interactively — they prompt via input(). They are not CI-friendly out of the box. To run them non-interactively, refactor __main__ to read environment variables or CLI arguments instead of calling input().


5. Operations

Operating this tooling at scale is mostly about keeping rule files in sync across repos and watching for upstream changes in alex and woke.

5.1 Monitoring rule drift across repos

If you adopted Pattern A (vendored rules), drift is the main risk. Detect it with a scheduled job:

# Compare every repo's alex-race-rules.yaml against the canonical version
gh repo list YOUR-ORG --json name --limit 1000 \
  | jq -r '.[].name' \
  | while read repo; do
      gh api "repos/YOUR-ORG/$repo/contents/alex-race-rules.yaml" 2>/dev/null \
        | jq -r '.content' \
        | base64 -d > "/tmp/$repo.yaml"
      diff -q canonical-alex-race-rules.yaml "/tmp/$repo.yaml" || echo "DRIFT: $repo"
    done

Run weekly via a GitHub Actions cron workflow.

5.2 Updating rules

When you decide to add or change a term:

  • [ ] Edit alex-race-rules.yaml and cisco-rules.yaml in the canonical repo.
  • [ ] Bump nothing — there is no version field. The git commit hash is the implicit version.
  • [ ] Run alex and woke against your reference corpus to confirm no surprise regressions.
  • [ ] Open PRs to the consuming repos (or wait for the next CDN sync if you use Pattern B).
  • [ ] Update the rollout tracker for any teams whose CI now fails on legitimate historical content.

Tip

Add a rule against terms like dummy, sanity check, or other ableist language by appending entries with the same type: basic schema. The alex rule pack is intentionally extensible.

5.3 Watching upstream

The repository pins alex@^11.0.1. alex follows semantic versioning, so 11.x patches are safe automatic updates and 12.0 needs manual review. For woke, the binary is unpinned — install whichever version you trust.

Note

GitHub Issue #142 ("Investigate the status of the woke linter") tracks the question of whether woke is still actively maintained. If woke goes unmaintained, migrating cisco-rules.yaml consumers to alex (or to a successor linter) is the contingency plan. Subscribe to that issue for status.

5.4 Audit reports

gh_search.py produces an audit log when run. Capture the output for periodic review:

python gh_search.py 2>&1 | tee inclusive-audit-$(date +%Y%m).log

The script also writes enterprisesearchresultsinfo.log (or githubsearchresultsinfo.log) automatically — different file names depending on which helper function was called.

5.5 Rotating helper-script credentials

Rotate the GitHub PAT in config.py every 90 days (or whenever your organization's credential policy demands).

# 1. Generate new PAT in GitHub UI
# 2. Update config.py
# 3. Smoke test
python gh_default_branch.py < /dev/null
# 4. Revoke the old PAT in GitHub UI

Caution

The helper scripts log API call rates to a logfile. Do not redirect stdout to a logfile that gets committed — the CSV output includes repository names that may be confidential in private orgs.


6. Performance

6.1 alex performance characteristics

alex's runtime is approximately linear in total prose bytes scanned. Typical numbers from a mid-size repo (~200 markdown files, ~2 MB total prose):

  • Cold first invocation (npx, includes download): 4-8 seconds.
  • Subsequent invocations: 0.8-2 seconds.
  • Per-file overhead: ~5-15 ms.

Files alex skips entirely (binary, unrecognized extension, listed in .alexignore) cost effectively zero.

6.2 woke performance characteristics

woke is a Go binary with concurrent file walking. It scans every line of every file regardless of language:

  • Single-machine throughput: 50-200 MB/s of source text.
  • Per-file startup overhead: ~1 ms.
  • Memory: O(rule count); 4 rules from cisco-rules.yaml is negligible.

6.3 Helper script throughput

The Python helpers are bottlenecked by GitHub's API rate limits:

Mode Rate limit Effective scan rate
gh_search.py (search API) 30 req/min auth'd ~30 keyword/extension combos per minute
gh_default_branch.py (search + repos) 5,000 req/hr core ~1 repo per second after initial query

The 2-second time.sleep(2) between result iterations in gh_search.py is deliberate padding to avoid burst-rate-limit errors on the per-result path fetches.

Note

Both helpers detect rate.remaining == 0 and sleep until the reset window automatically. The sleep can be multiple minutes. If a CI job needs a hard deadline, wrap the helper invocation in a timeout.

6.4 Scaling alex/woke in CI

For PR-only scanning, full-repo runs are usually fast enough. For mono-repos with millions of lines:

  • Use lint-staged (Section 5.3 of User Guide) to scan only the staged diff in pre-commit.
  • In CI, scan only files changed in the PR: git diff --name-only origin/main...HEAD | xargs -r alex.
  • For nightly full-repo runs, accept the multi-minute runtime.

7. Security

This tooling is read-only by design — the linters never modify files, and the helper scripts only read public or authenticated GitHub data. The attack surface is small but not zero.

7.1 Threat model summary

Threat Likelihood Impact Mitigation
Leaked GitHub PAT in config.py Medium (developer error) High (org-wide read access) .gitignore config.py, fine-scope tokens, rotate quarterly
Malicious YAML in alex-race-rules.yaml Low Low (alex parses safely) Review YAML PRs
Malicious JS in .alexrc.js Low High (arbitrary Node code at lint time) Review .alexrc.js PRs as carefully as application code
alex/woke supply-chain compromise Low High Pin alex@^11.0.1; verify woke binary checksums
Sensitive content scanned by woke Medium (repos with secrets) Medium (rule names visible in CI logs) Use .alexignore/woke ignore for sensitive paths

7.2 Scanning content with sensitive material

Both alex and woke read source files into memory and emit warnings citing file path, line number, and the matching word. They do not reproduce the surrounding line by default — the scanner output is designed to be safe to share. However:

  • woke's verbose output (default) includes the matching token but not the surrounding line. Logs can be safely captured.
  • alex's output also includes only the matching word and surrounding line numbers, not the line content itself.

Warning

If you ship CI logs to a third-party log aggregator, the aggregator will see file paths. For repositories whose directory structure is itself sensitive (e.g., secrets/production/api-key.env), exclude those paths from scanning via .alexignore and woke's .woke.yaml ignore list. Otherwise the file path leaks even though the contents do not.

# .alexignore
secrets/
.env
**/*.key
**/*.pem
config/credentials/
node_modules/
.git/

For woke, create .woke.yaml at the project root:

ignore_files:
  - secrets/
  - .env
  - "**/*.key"
  - "**/*.pem"
  - config/credentials/

7.4 Helper-script auth scope

The helper scripts use a personal access token. The minimum scope:

Target Required scope
Public github.com repos None (unauthenticated reads work, but rate-limited at 60/hr)
Authenticated github.com (higher rate) No scopes — just create a classic token with no boxes checked
Private repos in your own org Fine-grained token with Contents: Read-only for the target org
GitHub Enterprise repos Whatever your enterprise admin requires; usually repo scope

Caution

Do not grant repo (write), admin:org, or delete_repo scope. The scripts only read; any wider scope is excess privilege that could be abused if config.py leaks.

7.5 Secrets handling

The shipped exampleconfig.py contains an obvious placeholder string. The real config.py you create with a working token must be:

  • Listed in .gitignore before any commit.
  • Never logged, never shipped in error messages, never echoed.
  • Rotated when an employee with access leaves.
# Add to .gitignore in any repo where you check out inclusive-language
echo 'config.py' >> .gitignore
git add .gitignore
git commit -m "chore: ignore inclusive-language config.py"

7.6 Container/sandboxing recommendations

For organizations with strict scanner-isolation policies:

  • alex runs fine inside Docker with no network after the initial npm install.
  • woke is a single static binary with no network requirement.
  • The Python helpers must have HTTPS egress to GitHub's API.
# Network-isolated alex run
docker run --rm --network none -v "$PWD":/work -w /work node:20-alpine \
  sh -c 'npm install --no-audit alex@^11.0.1 && npx alex .'

Important

alex's plugins (loaded transitively by retext-equality) are JavaScript code that runs in the same Node process. If you treat node_modules/ as trust-equivalent to your application code (which you should), no additional sandboxing is required beyond what your normal Node CI runs do.


8. Developer Internals

For contributors and anyone modifying this repository.

8.1 Repository structure

inclusive-language/
├── .alexignore               # alex path exclusions (gitignore syntax)
├── .alexrc.js                # alex runtime config (CommonJS)
├── .gitignore                # standard
├── alex-race-rules.yaml      # 13 alex term-pair entries
├── bash-script-inventory.md  # internal inventory doc
├── cisco-rules.yaml          # 4 woke rule entries
├── CODE_OF_CONDUCT.md        # standard OSS doc
├── exampleconfig.py          # template config.py for the helpers
├── gh_default_branch.py      # default-branch audit script
├── gh_search.py              # keyword-search script
├── LICENSE                   # Apache 2.0 (per Cisco Open standard)
├── NOTICE                    # third-party attributions
├── package.json              # node deps: alex@^11.0.1
├── Pipfile                   # python deps (authoritative)
├── README.md                 # project description
├── requirements.txt          # python deps (autogenerated mirror)
└── SECURITY.md               # security disclosure policy

Every file lives at the project root; there are no subdirectories. This is unusual for a Python+Node hybrid but reflects the project's small scope.

8.2 The two helper scripts in detail

8.2.1 gh_default_branch.py

def repo_default_branch(filterkey):
    orgname = config.gh_orgname
    repositories = g.search_repositories(query='org:{}'.format(orgname))
    for repo in repositories:
        # rate-limit check + sleep
        ...
        if repo.private == False:
            if filterkey in repo.full_name:
                repo = g.get_repo(repo.full_name)
                defaultbranch = repo.default_branch
                if defaultbranch == 'master':
                    print('Repo: ', repo.full_name, 'has a default branch named master.')

Flow:

  1. Read gh_orgname and gh_api_key from config.
  2. Construct Github(ACCESS_TOKEN) client.
  3. Search every repo in the org via g.search_repositories(query='org:<org>').
  4. For each repo:
    • Check the core rate limit (rate_limit.core); sleep until reset if exhausted.
    • Skip private repos (if repo.private == False).
    • Skip repos whose full_name does not contain the user-supplied filterkey.
    • Fetch the full repo object and read default_branch.
    • Print a line if the default branch is 'master'.

The function returns no value — output is via print().

The __main__ block prompts for filterkey via input() and calls repo_default_branch(filterkey).

Note

The script also contains a commented-out repo.create_issue(...) call that would file a tracking issue against each offending repo. Uncomment with care — automated issue creation is hard to undo. Test on a single throwaway repository first.

8.2.2 gh_search.py

Two near-identical functions: search_github(keyword, filetype) and search_enterprise_github(keyword, filetype). The only difference is which Github client object they use:

g  = Github(ACCESS_TOKEN)                              # public github.com
eg = Github(base_url=API_ENDPOINT, login_or_token=ACCESS_TOKEN)  # enterprise

Both functions:

  1. Configure stdlib logging to a file (githubsearchresultsinfo.log for public, enterprisesearchresultsinfo.log for Enterprise).
  2. Read the search rate limit and sleep if exhausted.
  3. If filetype == 'any', query "{keyword}" org:{org}; otherwise query "{keyword}" org:{org} in:file extension:{filetype}.
  4. Iterate searchresults, sleeping 2 seconds between each, printing CSV-shaped lines.
  5. Catch and print any per-entry exception so the loop doesn't abort.

The __main__ block:

which_github = input(...)
keyword      = input(...)
filetype     = input(...)
which_github = 'Enterprise'   # <-- This line overrides the user's input
if which_github == "Enterprise":
    search_enterprise_github(keyword, filetype)
else:
    search_github(keyword, filetype)

Caution

The which_github = 'Enterprise' reassignment immediately before the if is a known bug. The branch for search_github (public) is dead code as shipped. To run public-GitHub searches, comment the override line out. This is consistent with what GitHub Issue #30 is trying to surface — there is no test/support matrix to catch this.

8.3 Code patterns and conventions

The Python code in this repository is written in a procedural, top-of-file configuration style:

  • config.py is imported at module top, and ACCESS_TOKEN = config.gh_api_key is read immediately. Failure to import or missing constants crashes the script before any function runs.
  • Functions take primitive arguments (str only), return None, and side-effect via print() and stdlib logging.
  • Exception handling is broad (except Exception as e: print(...)) — every per-iteration error is swallowed so the search loop continues.
  • No type hints, no docstrings, no unit tests are present in the repository.

8.4 Testing strategy

There are no tests in the repository. Issue #30 ("Build up a test and support matrix") tracks this gap. If you contribute code:

  • Add a tests/ directory at the project root.
  • Use pytest (already a transitive dep via the Pipfile ecosystem).
  • Mock pygithub.Github calls — the live GitHub API is not test-friendly.
  • For YAML rule changes, add a smoke test that runs npx alex against a fixture file and asserts the expected warnings.

8.5 Contribution checklist

Before opening a PR:

  • [ ] YAML edits validated with python -c "import yaml; yaml.safe_load(open('cisco-rules.yaml'))".
  • [ ] alex run on any sample text changed.
  • [ ] Python edits checked with python -m py_compile gh_search.py gh_default_branch.py.
  • [ ] No real PAT in exampleconfig.py (placeholder string only).
  • [ ] LICENSE and NOTICE unchanged unless adding a new third-party dependency.
  • [ ] Reference any related issue number in the PR description.

Tip

The placeholder PAT in exampleconfig.py is intentionally an obvious sentinel string ("ghp_TotallyaFaKeTok3nIprom1seYouS0d0ntTrYit"). When reviewing PRs, treat any non-sentinel string in this file as a leaked credential and reject the PR.

8.6 Potential improvements

  • Fix the hard-coded which_github = 'Enterprise' bug in gh_search.py (Section 8.2.2).
  • Convert helper scripts to argparse CLI so they run non-interactively in CI.
  • Add a test/support matrix (Issue #30) covering the YAML schemas and the helper scripts.
  • Pin woke in a sibling shell script with a checksum, the same way alex is pinned via package.json.
  • Migrate requirements.txt to use == instead of = so it's directly pip-consumable.
  • Document woke's status based on Issue #142 outcome — either confirm woke is supported or pivot the rule pack to a successor linter.
  • Rule severity — add severity: warning (or error) explicitly in cisco-rules.yaml so woke output is predictable across woke versions.

9. Integration Points

9.1 Inputs

Surface Provider Format
Files to scan The consuming repository Any text file (alex), any file (woke)
Configuration .alexrc.js, .alexignore, cisco-rules.yaml, config.py CommonJS, gitignore, YAML, Python module
Credentials GitHub PAT in config.py String
API endpoint gh_api_endpoint in config.py URL
User input (helpers) stdin via input() Plain text

9.2 Outputs

Channel Producer Consumer
Stdout warnings alex, woke Developer terminal, CI logs
Exit code alex, woke CI gate
Stdout CSV gh_search.py Audit pipelines, spreadsheet ingest
Stdout text gh_default_branch.py Audit pipelines
Log file gh_search.py githubsearchresultsinfo.log or enterprisesearchresultsinfo.log

9.3 External dependencies

Service Component Failure mode
npm registry alex install Install fails → fall back to npx --offline if a cached copy exists
woke release server woke install Install fails → use a vendored binary
GitHub REST API helper scripts Timeout/network → script crashes; rate limit → script sleeps until reset
PyPI Python deps Install fails → use a vendored wheelhouse

9.4 CI integrations

Already-known good integrations:

  • GitHub Actions — sample workflow in §4.3.
  • GitLab CI — same pattern; use node:20 and the npx alex . step.
  • Jenkins — call npx alex from a Node-shell stage; capture exit code.
  • Pre-commit framework — alex has community hooks at https://github.com/get-alex/alex. Use the pre-commit repo entry pointed at this rule pack.

9.5 Editor integrations

  • VS Code — the vscode-alex extension surfaces alex warnings inline. Point it at your project's .alexrc.js and alex-race-rules.yaml.
  • Sublime Text / Atom — alex has community plugins for both, though Atom is end-of-life.
  • JetBrains IDEs — no first-party plugin; teams typically run alex via the integrated terminal as a watch task.

9.6 Reporting integrations

woke can emit SARIF-format output that GitHub's code-scanning UI consumes natively. Wire it up in your CI:

- name: Run woke (SARIF)
  run: woke --output sarif --rule-in cisco-rules.yaml . > woke.sarif

- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: woke.sarif

This surfaces every finding in the GitHub Security tab of the repository. alex does not support SARIF natively as of 11.x; for alex findings, the common pattern is to parse stdout into a JSON Step Summary instead.