sase-github 0.2.12__tar.gz → 0.2.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sase_github-0.2.14/.release-please-manifest.json +3 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/CHANGELOG.md +14 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/CLAUDE.md +6 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/Justfile +7 -1
- {sase_github-0.2.12 → sase_github-0.2.14}/PKG-INFO +1 -1
- {sase_github-0.2.12 → sase_github-0.2.14}/pyproject.toml +1 -1
- sase_github-0.2.14/sase/sase.yml +22 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/workspace_plugin.py +9 -4
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_workspace_plugin.py +20 -0
- sase_github-0.2.14/tools/require_tool_run +60 -0
- sase_github-0.2.12/.release-please-manifest.json +0 -3
- {sase_github-0.2.12 → sase_github-0.2.14}/.github/workflows/ci.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/.github/workflows/pr-title.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/.github/workflows/publish.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/.sase_beads/beads.db +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/.sase_beads/config.json +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/.sase_beads/issues.jsonl +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/LICENSE +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/README.md +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/docs/architecture.md +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/docs/configuration.md +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/docs/xprompts.md +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/release-please-config.json +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/__init__.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/config.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/default_config.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/errors.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/plugin.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/scripts/__init__.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/scripts/gh_release.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/scripts/gh_setup.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/scripts/new_pr_desc_get_context.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/task_types.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/xprompts/gh.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/xprompts/new_pr_desc.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/xprompts/pr_diff.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/xprompts/prdd.yml +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/__init__.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_ci_install_contract.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_config.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_gh_workspace_claims.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_github_issues.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_github_plugin.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_github_pull_requests.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_new_pr_desc_get_context.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_submit_with_recorded_pr.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/tests/test_task_types.py +0 -0
- {sase_github-0.2.12 → sase_github-0.2.14}/uv.lock +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.14](https://github.com/sase-org/sase-github/compare/v0.2.13...v0.2.14) (2026-09-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **projects:** allocate canonical names case-insensitively ([fd5b7bd](https://github.com/sase-org/sase-github/commit/fd5b7bde2ac2e0785640df172e7e321275df406b))
|
|
9
|
+
|
|
10
|
+
## [0.2.13](https://github.com/sase-org/sase-github/compare/v0.2.12...v0.2.13) (2026-09-22)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **tool:** add check catalog and recipe guard ([e807f82](https://github.com/sase-org/sase-github/commit/e807f823f6ee137c72503d8367d0a80543196b97))
|
|
16
|
+
|
|
3
17
|
## [0.2.12](https://github.com/sase-org/sase-github/compare/v0.2.11...v0.2.12) (2026-09-15)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -23,3 +23,9 @@ just check # lint + test
|
|
|
23
23
|
- Absolute imports: `from sase_github.plugin import GitHubPlugin`
|
|
24
24
|
- Target Python 3.12+
|
|
25
25
|
- Follow ruff rules matching sase core
|
|
26
|
+
|
|
27
|
+
## sase tool runs
|
|
28
|
+
|
|
29
|
+
Agents run `sase tool run check` here, not bare `just check`: `check` is
|
|
30
|
+
guarded and a raw agent invocation is refused with the wrapped and bypass
|
|
31
|
+
forms. To run raw on purpose: `SASE_TOOL_BYPASS='<why>' just check`.
|
|
@@ -65,7 +65,13 @@ fmt: _setup
|
|
|
65
65
|
test *args: _setup
|
|
66
66
|
{{ venv_bin }}/pytest {{ args }}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
# Agents must run guarded tools through `sase tool run` (sase docs/tool.md).
|
|
69
|
+
# The guard is the first dependency, ahead of `_setup`, so a refusal costs
|
|
70
|
+
# milliseconds rather than a dependency sync.
|
|
71
|
+
_require-tool-run name:
|
|
72
|
+
@tools/require_tool_run {{ name }}
|
|
73
|
+
|
|
74
|
+
check: (_require-tool-run "check") lint test
|
|
69
75
|
|
|
70
76
|
clean:
|
|
71
77
|
rm -rf build/ dist/ *.egg-info src/*.egg-info .mypy_cache/ .ruff_cache/ .pytest_cache/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Project-owned named tools (see sase docs/tool.md, "Guarded recipes").
|
|
2
|
+
# Complete entries: other config layers cannot alter this catalog.
|
|
3
|
+
tools:
|
|
4
|
+
check:
|
|
5
|
+
argv: [just, check]
|
|
6
|
+
description: Run the repository scoped check.
|
|
7
|
+
stages: none
|
|
8
|
+
inputs:
|
|
9
|
+
- Justfile
|
|
10
|
+
- pyproject.toml
|
|
11
|
+
- uv.lock
|
|
12
|
+
args: deny
|
|
13
|
+
fingerprint:
|
|
14
|
+
toolchain:
|
|
15
|
+
python: [.venv/bin/python, --version]
|
|
16
|
+
just: [just, --version]
|
|
17
|
+
sase-github:
|
|
18
|
+
[
|
|
19
|
+
.venv/bin/python,
|
|
20
|
+
-c,
|
|
21
|
+
"from importlib.metadata import version; print(version('sase-github'))",
|
|
22
|
+
]
|
|
@@ -1505,12 +1505,17 @@ def _canonical_project_name_base(user: str, project: str) -> str:
|
|
|
1505
1505
|
|
|
1506
1506
|
|
|
1507
1507
|
def _project_refs(records: Sequence[ProjectRecordWire]) -> set[str]:
|
|
1508
|
+
"""Return folded project refs occupying the canonical-name namespace.
|
|
1509
|
+
|
|
1510
|
+
Refs compare case-insensitively, so a canonical name is never allocated
|
|
1511
|
+
as a case-variant duplicate of an existing key, name, or alias.
|
|
1512
|
+
"""
|
|
1508
1513
|
occupied: set[str] = set()
|
|
1509
1514
|
for record in records:
|
|
1510
|
-
occupied.add(record.project_name)
|
|
1515
|
+
occupied.add(record.project_name.casefold())
|
|
1511
1516
|
if display_name := getattr(record, "display_name", None):
|
|
1512
|
-
occupied.add(display_name)
|
|
1513
|
-
occupied.update(record.aliases)
|
|
1517
|
+
occupied.add(display_name.casefold())
|
|
1518
|
+
occupied.update(alias.casefold() for alias in record.aliases)
|
|
1514
1519
|
return occupied
|
|
1515
1520
|
|
|
1516
1521
|
|
|
@@ -1524,7 +1529,7 @@ def _allocate_canonical_project_name(
|
|
|
1524
1529
|
|
|
1525
1530
|
candidate = base
|
|
1526
1531
|
suffix = 2
|
|
1527
|
-
while candidate in occupied:
|
|
1532
|
+
while candidate.casefold() in occupied:
|
|
1528
1533
|
candidate = f"{base}-{suffix}"
|
|
1529
1534
|
suffix += 1
|
|
1530
1535
|
return candidate
|
|
@@ -1830,6 +1830,26 @@ class TestResolveGhRef:
|
|
|
1830
1830
|
encoding="utf-8"
|
|
1831
1831
|
)
|
|
1832
1832
|
|
|
1833
|
+
@patch(
|
|
1834
|
+
"sase_github.workspace_plugin.get_default_branch", return_value="origin/main"
|
|
1835
|
+
)
|
|
1836
|
+
def test_repo_path_suffixes_case_variant_canonical_project_name(
|
|
1837
|
+
self, mock_branch: MagicMock
|
|
1838
|
+
) -> None:
|
|
1839
|
+
with tempfile.TemporaryDirectory() as d:
|
|
1840
|
+
home = Path(d)
|
|
1841
|
+
_github_workspace(home, "alice", "foo")
|
|
1842
|
+
_write_project(
|
|
1843
|
+
home,
|
|
1844
|
+
"GH_ALICE__FOO",
|
|
1845
|
+
"WORKSPACE_DIR: /some/other/path/\nNAME: other\n",
|
|
1846
|
+
)
|
|
1847
|
+
path_patch, env_patch = _home_patches(home)
|
|
1848
|
+
with path_patch, env_patch:
|
|
1849
|
+
result = resolve_gh_ref("alice/foo")
|
|
1850
|
+
|
|
1851
|
+
assert result.project_name == "gh_alice__foo-2"
|
|
1852
|
+
|
|
1833
1853
|
@patch(
|
|
1834
1854
|
"sase_github.workspace_plugin.get_default_branch", return_value="origin/main"
|
|
1835
1855
|
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Guard a Just recipe so SASE agents only run it through `sase tool run`.
|
|
3
|
+
#
|
|
4
|
+
# Usage: tools/require_tool_run <tool-name>
|
|
5
|
+
#
|
|
6
|
+
# Wired as the first dependency of each guarded recipe (see `check` and
|
|
7
|
+
# `check-full` in the Justfile), ahead of `_setup`, so a refusal costs
|
|
8
|
+
# milliseconds rather than a dependency sync. Contract: docs/tool.md
|
|
9
|
+
# ("Guarded recipes" table). Deliberately dependency-free POSIX `sh`: this
|
|
10
|
+
# must never start `sase`, because the override exists precisely for when
|
|
11
|
+
# `sase` is broken, and because every human and CI `just check` would
|
|
12
|
+
# otherwise pay a startup cost for logic that needs three variables.
|
|
13
|
+
#
|
|
14
|
+
# An agent may run a guarded recipe only from inside `sase tool run <that
|
|
15
|
+
# tool>` for that project root, or with an explicit bypass. This is a
|
|
16
|
+
# guardrail against habit, not a security boundary: `env -u SASE_AGENT`
|
|
17
|
+
# defeats it, and the bypass is deliberately easier and more visible.
|
|
18
|
+
set -u
|
|
19
|
+
|
|
20
|
+
tool=${1:-}
|
|
21
|
+
if [ -z "$tool" ]; then
|
|
22
|
+
printf 'sase: usage: tools/require_tool_run <tool-name>\n' >&2
|
|
23
|
+
exit 2
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Humans, CI, finalizers, monitors, and procs run raw: only an agent's own
|
|
27
|
+
# shell carries SASE_AGENT.
|
|
28
|
+
if [ -z "${SASE_AGENT:-}" ]; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Inside `sase tool run <this tool>` for this project root. SASE_TOOL_NAME
|
|
33
|
+
# is exported whether or not recording succeeded, so the child of a
|
|
34
|
+
# fail-open run is still allowed. Ad-hoc runs export SASE_TOOL_NAME=ad-hoc
|
|
35
|
+
# with an empty root and can never match a guarded recipe's name.
|
|
36
|
+
if [ "${SASE_TOOL_NAME:-}" = "$tool" ] && [ "${SASE_TOOL_PROJECT_ROOT:-}" = "$(pwd -P)" ]; then
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Explicit bypass: any non-empty value runs raw on purpose, and the value
|
|
41
|
+
# is the reason. Keep the notice to one line even if the reason is not.
|
|
42
|
+
if [ -n "${SASE_TOOL_BYPASS:-}" ]; then
|
|
43
|
+
nl='
|
|
44
|
+
'
|
|
45
|
+
reason=${SASE_TOOL_BYPASS%%"$nl"*}
|
|
46
|
+
printf 'sase: bypassing the tool-run guard (SASE_TOOL_BYPASS=%s).\n' "$reason" >&2
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Fail open without `sase`: when the wrapper is unavailable there is no
|
|
51
|
+
# wrapped form to print, so allow the raw run and say why.
|
|
52
|
+
if ! command -v sase >/dev/null 2>&1; then
|
|
53
|
+
printf 'sase: allowing raw `just %s`: `sase` is not on PATH.\n' "$tool" >&2
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
printf 'sase: refusing raw `just %s` in an agent shell (SASE_AGENT is set and SASE_TOOL_NAME names a different tool or root).\n' "$tool" >&2
|
|
58
|
+
printf 'sase: run `sase tool run %s` instead.\n' "$tool" >&2
|
|
59
|
+
printf 'sase: or run `SASE_TOOL_BYPASS='"'"'<reason>'"'"' just %s` to bypass with a named reason.\n' "$tool" >&2
|
|
60
|
+
exit 2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sase_github-0.2.12 → sase_github-0.2.14}/src/sase_github/scripts/new_pr_desc_get_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|