mirror of
https://github.com/Katakate/k7.git
synced 2026-09-22 01:53:19 +00:00
a939e693d0
Security release for the k7-api control plane. Fixes a server-side request forgery reachable through a sandbox's image registry host: registry hosts are now resolved and checked against public/allowlisted ranges before any OCI fetch, the localhost-to-plain-HTTP downgrade is gone, and redirects are disabled so an allowlisted host cannot bounce the request inward. Adds optional per-key namespace authorization, so an API key can be confined to the namespaces it owns and cannot perform all-namespaces operations. Keys without a scope keep their previous unrestricted behaviour, so upgrading changes nothing until you scope your keys. Both issues were reported privately by Jirayu Thongchotchaung, who held disclosure until this release was available. See CHANGELOG.md and the published advisories for detail.
65 lines
2.2 KiB
Python
65 lines
2.2 KiB
Python
"""Unit tests for API key generation / namespace scoping (spec 10h)."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from k7.cli.k7 import app
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
class TestGenerateApiKeyNamespaces:
|
|
def test_scoped_namespaces_persisted(self, tmp_path: Path):
|
|
keys_file = tmp_path / "api_keys.json"
|
|
with patch("k7.cli.k7.API_KEYS_FILE", keys_file):
|
|
result = runner.invoke(
|
|
app,
|
|
["generate-api-key", "scoped", "-n", "a", "--namespace", "b"],
|
|
)
|
|
assert result.exit_code == 0, result.output
|
|
data = json.loads(keys_file.read_text())
|
|
assert len(data) == 1
|
|
entry = next(iter(data.values()))
|
|
assert entry["name"] == "scoped"
|
|
assert entry["namespaces"] == ["a", "b"]
|
|
|
|
def test_unscoped_key_omits_namespaces_field(self, tmp_path: Path):
|
|
keys_file = tmp_path / "api_keys.json"
|
|
with patch("k7.cli.k7.API_KEYS_FILE", keys_file):
|
|
result = runner.invoke(app, ["generate-api-key", "open"])
|
|
assert result.exit_code == 0, result.output
|
|
data = json.loads(keys_file.read_text())
|
|
entry = next(iter(data.values()))
|
|
assert "namespaces" not in entry
|
|
|
|
def test_list_shows_namespaces_column(self, tmp_path: Path):
|
|
keys_file = tmp_path / "api_keys.json"
|
|
keys_file.write_text(
|
|
json.dumps(
|
|
{
|
|
"h1": {
|
|
"name": "scoped",
|
|
"created": 1,
|
|
"expires": 2,
|
|
"last_used": None,
|
|
"namespaces": ["alpha"],
|
|
},
|
|
"h2": {
|
|
"name": "open",
|
|
"created": 1,
|
|
"expires": 2,
|
|
"last_used": None,
|
|
},
|
|
}
|
|
)
|
|
)
|
|
with patch("k7.cli.k7.API_KEYS_FILE", keys_file):
|
|
result = runner.invoke(app, ["list-api-keys"])
|
|
assert result.exit_code == 0, result.output
|
|
assert "Namespaces" in result.output
|
|
assert "alpha" in result.output
|
|
assert "*" in result.output
|