mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 22:55:14 +00:00
feat: add GUIDE.md for GitHub automation and update references in AGENTS.md and README.md
This commit is contained in:
5 files changed
+48
-5
No files matched your search
File renamed without changes.
@@ -2,12 +2,14 @@ version: 2
|
|||||||
updates:
|
updates:
|
||||||
- package-ecosystem: github-actions
|
- package-ecosystem: github-actions
|
||||||
directory: /
|
directory: /
|
||||||
|
target-branch: dev
|
||||||
schedule:
|
schedule:
|
||||||
interval: weekly
|
interval: weekly
|
||||||
open-pull-requests-limit: 5
|
open-pull-requests-limit: 5
|
||||||
|
|
||||||
- package-ecosystem: pip
|
- package-ecosystem: pip
|
||||||
directory: /requirements
|
directory: /requirements
|
||||||
|
target-branch: dev
|
||||||
schedule:
|
schedule:
|
||||||
interval: monthly
|
interval: monthly
|
||||||
open-pull-requests-limit: 5
|
open-pull-requests-limit: 5
|
||||||
@@ -31,7 +31,7 @@ and validation boundary.
|
|||||||
|
|
||||||
| Directory | Guide | Role |
|
| Directory | Guide | Role |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `.github/` | [.github/README.md](.github/README.md) | CI, release automation, reusable actions, and ownership metadata. |
|
| `.github/` | [.github/GUIDE.md](.github/GUIDE.md) | CI, release automation, reusable actions, and ownership metadata. |
|
||||||
| `app/` | [app/README.md](app/README.md) | Firmware applications and integrations. |
|
| `app/` | [app/README.md](app/README.md) | Firmware applications and integrations. |
|
||||||
| `config/` | [config/README.md](config/README.md) | Locked external inputs and checksums. |
|
| `config/` | [config/README.md](config/README.md) | Locked external inputs and checksums. |
|
||||||
| `configs/` | [configs/README.md](configs/README.md) | Reproducible build profiles. |
|
| `configs/` | [configs/README.md](configs/README.md) | Reproducible build profiles. |
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
|||||||
| [`pdk/`](pdk) | PDK setup entry points and technology-specific integration. |
|
| [`pdk/`](pdk) | PDK setup entry points and technology-specific integration. |
|
||||||
| [`syn/`](syn) and [`sta/`](sta) | Synthesis and static timing analysis flows. |
|
| [`syn/`](syn) and [`sta/`](sta) | Synthesis and static timing analysis flows. |
|
||||||
| [`scripts/`](scripts) and [`quality/`](quality) | Build helpers, regression orchestration, checks, warning baselines, and metric policy. |
|
| [`scripts/`](scripts) and [`quality/`](quality) | Build helpers, regression orchestration, checks, warning baselines, and metric policy. |
|
||||||
|
| [`.github/`](.github) | GitHub automation, Dependabot configuration, and CI/release workflows; see [`GUIDE.md`](.github/GUIDE.md). |
|
||||||
| [`docs/`](docs) | Engineering workflow and release-process documentation. |
|
| [`docs/`](docs) | Engineering workflow and release-process documentation. |
|
||||||
|
|
||||||
## Supported Configurations
|
## Supported Configurations
|
||||||
|
|||||||
@@ -521,21 +521,61 @@ def test_ci_actions_are_pinned_to_commits() -> None:
|
|||||||
assert re.fullmatch(r"[^@]+@[0-9a-f]{40}", value), f"unpinned action in {path}: {value}"
|
assert re.fullmatch(r"[^@]+@[0-9a-f]{40}", value), f"unpinned action in {path}: {value}"
|
||||||
|
|
||||||
|
|
||||||
|
HASH_LOCKED_REQUIREMENT = re.compile(
|
||||||
|
r"[^\s=]+==[^\s]+(?:\s+--hash=sha256:[0-9a-f]{64})+"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def hash_locked_requirement_lines(content: str) -> list[str]:
|
||||||
|
logical_content = re.sub(r"\\\r?\n[ \t]*", " ", content)
|
||||||
|
return [
|
||||||
|
line.strip()
|
||||||
|
for line in logical_content.splitlines()
|
||||||
|
if line.strip() and not line.lstrip().startswith(("#", "--"))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_python_requirements_are_hash_locked() -> None:
|
def test_python_requirements_are_hash_locked() -> None:
|
||||||
for path in sorted((ROOT / "requirements").glob("*.txt")):
|
for path in sorted((ROOT / "requirements").glob("*.txt")):
|
||||||
content = path.read_text(encoding="utf-8")
|
content = path.read_text(encoding="utf-8")
|
||||||
assert "--require-hashes" in content
|
assert "--require-hashes" in content
|
||||||
assert "--only-binary=:all:" in content
|
assert "--only-binary=:all:" in content
|
||||||
requirements = [
|
requirements = hash_locked_requirement_lines(content)
|
||||||
line for line in content.splitlines() if line and not line.startswith(("#", "--"))
|
|
||||||
]
|
|
||||||
assert requirements
|
assert requirements
|
||||||
for requirement in requirements:
|
for requirement in requirements:
|
||||||
assert re.search(r"==[^ ]+ --hash=sha256:[0-9a-f]{64}$", requirement), (
|
assert HASH_LOCKED_REQUIREMENT.fullmatch(requirement), (
|
||||||
f"unlocked requirement in {path}: {requirement}"
|
f"unlocked requirement in {path}: {requirement}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_requirement_hash_validation_accepts_multiple_hashes() -> None:
|
||||||
|
first_hash = "a" * 64
|
||||||
|
second_hash = "b" * 64
|
||||||
|
requirements = hash_locked_requirement_lines(
|
||||||
|
"--only-binary=:all:\n"
|
||||||
|
"--require-hashes\n"
|
||||||
|
"ruff==0.15.21 \\\n"
|
||||||
|
f" --hash=sha256:{first_hash} \\\n"
|
||||||
|
f" --hash=sha256:{second_hash}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(requirements) == 1
|
||||||
|
assert HASH_LOCKED_REQUIREMENT.fullmatch(requirements[0])
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_requirement_hash_validation_rejects_unlocked_entries() -> None:
|
||||||
|
valid_hash = "a" * 64
|
||||||
|
invalid_requirements = (
|
||||||
|
"ruff>=0.15.21 --hash=sha256:" + valid_hash,
|
||||||
|
"ruff==0.15.21",
|
||||||
|
"ruff==0.15.21 --hash=sha256:" + "a" * 63,
|
||||||
|
"ruff==0.15.21 --hash=sha256:" + valid_hash + " --extra",
|
||||||
|
)
|
||||||
|
|
||||||
|
for requirement in invalid_requirements:
|
||||||
|
assert not HASH_LOCKED_REQUIREMENT.fullmatch(requirement)
|
||||||
|
|
||||||
|
|
||||||
def test_clean_all_stays_within_repository(tmp_path: Path) -> None:
|
def test_clean_all_stays_within_repository(tmp_path: Path) -> None:
|
||||||
fake_root = tmp_path / "repository"
|
fake_root = tmp_path / "repository"
|
||||||
(fake_root / ".git").mkdir(parents=True)
|
(fake_root / ".git").mkdir(parents=True)
|
||||||
|
|||||||
Reference in new issue
Block a user