)]}'
{
  "commit": "4cbd3db2abb66b8520edadf1ddb4688ef7a4e741",
  "tree": "52554e509fb86cf6bc2f58ad8d950a7e9ce1ca17",
  "parents": [
    "86036ca7a95528c1f3447bd13ae01f24950a41ee"
  ],
  "author": {
    "name": "Jarek Potiuk",
    "email": "jarek@potiuk.com",
    "time": "Wed Apr 29 01:26:41 2026 +0200"
  },
  "committer": {
    "name": "Jarek Potiuk",
    "email": "jarek@potiuk.com",
    "time": "Wed Apr 29 01:26:41 2026 +0200"
  },
  "message": "tools(oauth-draft): port Gmail OAuth helpers into framework\n\nPorts the three Gmail OAuth scripts that previously lived at\n`airflow-s/airflow-s:tools/gmail/oauth-draft/` into the framework as\nan installable Python project, mirroring the shape of the\n`generate-cve-json` port (PR #2).\n\nThe tool was already largely project-agnostic — the only adopter-\nspecific bit was the default credentials path\n(`~/.config/airflow-s/gmail-oauth.json`), which was a holdover from\nwhen the tracker repo was named `airflow-s`. It now defaults to\n`~/.config/apache-steward/gmail-oauth.json`, aligning with the\n`\u003cproject-config\u003e/apache-steward/` submodule convention.\n\nFiles added:\n\n- `tools/gmail/oauth-draft/pyproject.toml` — three console scripts\n  (`oauth-draft-setup`, `oauth-draft-create`, `oauth-draft-mark-read`).\n  `google-auth-oauthlib` is the only runtime dep (used by setup);\n  the other two commands are stdlib-only.\n- `tools/gmail/oauth-draft/src/oauth_draft/credentials.py` — shared\n  `Credentials` dataclass, `locate_credentials` resolution, and\n  `refresh_access_token` so the three commands don\u0027t duplicate the\n  OAuth boilerplate.\n- `tools/gmail/oauth-draft/src/oauth_draft/{setup_creds,create_draft,\n  mark_threads_read}.py` — one module per command, each with a thin\n  `main(argv)` callable used by both the console-script entry point\n  and the test suite.\n- `tools/gmail/oauth-draft/src/oauth_draft/__init__.py` — re-exports\n  the three `main` functions.\n- `tools/gmail/oauth-draft/tests/{__init__,test_credentials,\n  test_create_draft,test_mark_threads_read}.py` — 22 tests covering\n  credential loading, path resolution, MIME building, the pure\n  thread-header helper, and arg-parsing defaults. No tests hit the\n  Gmail API. The originals carried no tests; this thin set gives the\n  pre-commit `pytest` hook real coverage.\n- `tools/gmail/oauth-draft/README.md` — Run / Setup / How threading\n  is guaranteed / Test / Lint sections, mirroring the\n  generate-cve-json README. The one-time OAuth setup walkthrough\n  that used to live in the airflow-s `oauth-draft/README.md` is\n  folded in here.\n- `tools/gmail/oauth-draft/{.gitignore,uv.lock}` — standard.\n\nFiles updated:\n\n- `.pre-commit-config.yaml` — added the four `oauth-draft-*` hooks\n  (ruff-check, ruff-format, mypy, pytest), scoped to\n  `^tools/gmail/oauth-draft/(src|tests|pyproject\\.toml)`.\n- `tools/gmail/{draft-backends,operations}.md` — switched legacy\n  script-path references (`tools/gmail/oauth-draft/create_draft.py`,\n  `setup_credentials.py`) to the console-script invocation form\n  (`uv run --project \u003cframework\u003e/tools/gmail/oauth-draft\n  oauth-draft-*`). Default credentials path updated to\n  `~/.config/apache-steward/gmail-oauth.json`.\n- `.claude/skills/{sync,allocate-cve,import,invalidate}-\n  security-issue/SKILL.md` — same default-path update; the sync\n  skill also gets the console-script invocation.\n\nTest plan:\n\n- 22 tests pass against the new suite.\n- All four pre-commit hooks pass (ruff/ruff-format/mypy/pytest)\n  plus the standard repo hooks (doctoc, end-of-file-fixer, etc.).\n- All three console scripts respond to `--help` correctly.\n\nCoordination:\n\nA follow-up PR against `airflow-s/airflow-s` will delete the local\n`tools/gmail/oauth-draft/` scripts there (they live in the framework\nnow via submodule) and update local references to point at the\nframework copy. Existing airflow-s users with credentials at the\nold `~/.config/airflow-s/gmail-oauth.json` path can either move the\nfile to `~/.config/apache-steward/` or set\n`\\$GMAIL_OAUTH_CREDENTIALS` — that follow-up PR\u0027s body will flag\nthis.\n\nGenerated-by: Claude Code (Claude Opus 4.7)\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "402188a39442305793860adc18002d731b730d9a",
      "old_mode": 33188,
      "old_path": ".claude/skills/allocate-cve/SKILL.md",
      "new_id": "2fe5b392edac75e86a10c94d18ed4352155570b2",
      "new_mode": 33188,
      "new_path": ".claude/skills/allocate-cve/SKILL.md"
    },
    {
      "type": "modify",
      "old_id": "5d04fca54ca55995ebf3a953102a703fb5104bcd",
      "old_mode": 33188,
      "old_path": ".claude/skills/import-security-issue/SKILL.md",
      "new_id": "4708ba700c861f721c448ca9b29f1874a7acc2bf",
      "new_mode": 33188,
      "new_path": ".claude/skills/import-security-issue/SKILL.md"
    },
    {
      "type": "modify",
      "old_id": "71e0d99d0e9c63563b7824cee8c3e7d15441420b",
      "old_mode": 33188,
      "old_path": ".claude/skills/invalidate-security-issue/SKILL.md",
      "new_id": "2fba5f61e094249dca8ec8960c2a6c513e1fd81a",
      "new_mode": 33188,
      "new_path": ".claude/skills/invalidate-security-issue/SKILL.md"
    },
    {
      "type": "modify",
      "old_id": "3c3b9d0efa2c6672b3a8a851f4c335fed72c2568",
      "old_mode": 33188,
      "old_path": ".claude/skills/sync-security-issue/SKILL.md",
      "new_id": "bad2e1d7accc8662f238992673a878fe53eeab8f",
      "new_mode": 33188,
      "new_path": ".claude/skills/sync-security-issue/SKILL.md"
    },
    {
      "type": "modify",
      "old_id": "cb45c2a94b2e2f9dd5991d4399d4814d4ab8ba43",
      "old_mode": 33188,
      "old_path": ".pre-commit-config.yaml",
      "new_id": "ebe72ea7144ef6d883f4597b34353f36095bc97e",
      "new_mode": 33188,
      "new_path": ".pre-commit-config.yaml"
    },
    {
      "type": "modify",
      "old_id": "06215b1cd1ba0b4afdc9be0da7aa2f93ba911d5b",
      "old_mode": 33188,
      "old_path": "tools/gmail/draft-backends.md",
      "new_id": "dab4fd5b7150491313b8b34ba2f841fbf4cd1954",
      "new_mode": 33188,
      "new_path": "tools/gmail/draft-backends.md"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "ab7ef44e9609eb729158d97c407f3dc444598bbb",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/.gitignore"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "f930926ea00b4c4d63b9e3a875de7c09817e718c",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/README.md"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "a7e4518562733d6f6a44a6e43b82b6ad1491eb12",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/pyproject.toml"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "f33a3293e59077c257acea8a6d203bb0e6e54efd",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/src/oauth_draft/__init__.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "e24fcc6b35f18e0259a74e070e81df44b4e26593",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/src/oauth_draft/create_draft.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "7c082b267e5d0480a0f04c2dbfc70b7e5ec320c3",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/src/oauth_draft/credentials.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "9da65c94ca3542dfca93952c107182ac2858e146",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/src/oauth_draft/mark_threads_read.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "83e91f2fe7b1d18b9587a228654543f16eac5f0a",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/src/oauth_draft/setup_creds.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/tests/__init__.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "d6675d24c5133a01315dcc673d0ca9ca28f3ed44",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/tests/test_create_draft.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "15f794b7cdc8c4c2da6fb61a07275a892e79626e",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/tests/test_credentials.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "b5ea46a6504c20e4570d0b8be4dd114b61058368",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/tests/test_mark_threads_read.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "658d7d5bdfcc81a966be83127ef5d67eccb8c43c",
      "new_mode": 33188,
      "new_path": "tools/gmail/oauth-draft/uv.lock"
    },
    {
      "type": "modify",
      "old_id": "288b1bd7a281d441c356a56d06703204fba4d8b5",
      "old_mode": 33188,
      "old_path": "tools/gmail/operations.md",
      "new_id": "44e43e3da354b4f6f73effdcbf83583999655fe6",
      "new_mode": 33188,
      "new_path": "tools/gmail/operations.md"
    }
  ]
}
