9287cf7cf2
## Summary - Adds \`package: puppet\` for proxying Puppet Forge (forgeapi.puppet.com) - \`remote/puppet.py\` rewrites JSON responses: absolute forge URLs → proxy URLs, and relative \`/v3/files/\` \`file_uri\` paths → absolute proxy URLs. g10k uses Go's \`url.ResolveReference\`, so an absolute \`file_uri\` overrides the base URL entirely — tarballs are fetched directly from the proxy without a second hop - Built-in mutable patterns: \`^v3/modules/\` and \`^v3/releases\` (module metadata); tarballs at \`v3/files/\` are configured as immutable via \`immutable_patterns\` - 9 new tests covering mutable detection, URL rewriting (relative \`file_uri\` and absolute forge URLs), content-type, tarball pass-through, and pattern blocking ## Client configuration **g10k config file** (\`forge_base_url\` at root level): \`\`\`yaml cachedir: /tmp/g10k forge_base_url: https://artifacts.example.com/api/v1/remote/puppet-forge sources: control: remote: git@git.example.com:puppet/control.git basedir: /etc/puppetlabs/code/environments \`\`\` **Puppetfile** (\`forge.baseUrl\` directive, works with \`-puppetfile\` mode): \`\`\`ruby forge.baseUrl https://artifacts.example.com/api/v1/remote/puppet-forge mod 'puppetlabs-stdlib', '9.7.0' \`\`\` ## Test plan - [x] 331 unit tests pass (\`make test\`) - [x] End-to-end: g10k 0.9.10 on AlmaLinux 9 via \`forge_base_url\` — stdlib 9.7.0, inifile 6.2.0, concat 9.1.0 installed; proxy logs confirm cache MISS → fetch → ADD for metadata and tarballs - [x] End-to-end: \`forge.baseUrl\` Puppetfile directive with \`-puppetfile\` mode — same result Reviewed-on: #44
206 lines
6.7 KiB
Python
206 lines
6.7 KiB
Python
"""
|
|
Pytest configuration and shared fixtures.
|
|
|
|
Module-level setup (env vars + connection patches) runs before any test
|
|
module is imported, so the FastAPI app initialises against mocks rather
|
|
than real S3 / Redis / PostgreSQL services.
|
|
"""
|
|
|
|
import os
|
|
import tempfile
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import yaml
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Test remote configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
TEST_REMOTES = {
|
|
"remotes": {
|
|
"alpine-test": {
|
|
"base_url": "https://dl-cdn.alpinelinux.org",
|
|
"package": "alpine",
|
|
"immutable_patterns": [".*/x86_64/.*\\.apk$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 3600},
|
|
},
|
|
"rpm-test": {
|
|
"base_url": "https://example.com/rpm",
|
|
"package": "rpm",
|
|
"immutable_patterns": [".*/x86_64/.*\\.rpm$", ".*/repodata/.*$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 3600},
|
|
},
|
|
"docker-test": {
|
|
"base_url": "https://registry.example.com",
|
|
"package": "docker",
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 300},
|
|
},
|
|
"docker-restricted": {
|
|
"base_url": "https://registry.example.com",
|
|
"package": "docker",
|
|
"immutable_patterns": ["^library/nginx"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 300},
|
|
},
|
|
"docker-bantags-test": {
|
|
"base_url": "https://registry.example.com",
|
|
"package": "docker",
|
|
"ban_tags_enabled": True,
|
|
"ban_tags": ["latest", "edge"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 300},
|
|
},
|
|
"generic-test": {
|
|
"base_url": "https://releases.example.com",
|
|
"package": "generic",
|
|
"immutable_patterns": [".*\\.tar\\.gz$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 0},
|
|
},
|
|
"custom-index-test": {
|
|
"base_url": "https://example.com",
|
|
"package": "generic",
|
|
"mutable_patterns": ["metadata\\.json$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 600},
|
|
},
|
|
"check-mutable-test": {
|
|
"base_url": "https://example.com",
|
|
"package": "generic",
|
|
"mutable_patterns": ["metadata\\.json$"],
|
|
"check_mutable_updates": True,
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 600},
|
|
},
|
|
"pypi-test": {
|
|
"base_url": "https://files.pythonhosted.org",
|
|
"package": "pypi",
|
|
"immutable_patterns": [
|
|
r"packages/.*\.whl$",
|
|
r"packages/.*\.whl\.metadata$",
|
|
r"packages/.*\.tar\.gz$",
|
|
],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 600},
|
|
},
|
|
"npm-test": {
|
|
"base_url": "https://registry.npmjs.org",
|
|
"package": "npm",
|
|
"immutable_patterns": [r"\.tgz$"],
|
|
"mutable_patterns": [r"^(?!.*\.tgz$).*"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 600},
|
|
},
|
|
"helm-test": {
|
|
"base_url": "https://helm.releases.hashicorp.com",
|
|
"package": "helm",
|
|
"immutable_patterns": [r"\.tgz$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 3600},
|
|
},
|
|
"quarantine-test": {
|
|
"base_url": "https://releases.example.com",
|
|
"package": "generic",
|
|
"immutable_patterns": [r".*\.tar\.gz$"],
|
|
"quarantine_new": True,
|
|
"quarantine_days": 3,
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 0},
|
|
},
|
|
"quarantine-disabled": {
|
|
"base_url": "https://releases.example.com",
|
|
"package": "generic",
|
|
"immutable_patterns": [r".*\.tar\.gz$"],
|
|
"quarantine_new": False,
|
|
"quarantine_days": 3,
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 0},
|
|
},
|
|
"helm-member-2": {
|
|
"base_url": "https://charts.example.com",
|
|
"package": "helm",
|
|
"immutable_patterns": [r"\.tgz$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 1800},
|
|
},
|
|
"puppet-test": {
|
|
"base_url": "https://forgeapi.puppet.com",
|
|
"package": "puppet",
|
|
"immutable_patterns": [r"^v3/files/.*\.tar\.gz$"],
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 600},
|
|
},
|
|
},
|
|
"locals": {
|
|
"local-test": {
|
|
"package": "generic",
|
|
"cache": {"immutable_ttl": 0, "mutable_ttl": 0},
|
|
},
|
|
},
|
|
"virtuals": {
|
|
"helm-virtual-test": {
|
|
"package": "helm",
|
|
"members": ["helm-test", "helm-member-2"],
|
|
},
|
|
"unsupported-virtual-test": {
|
|
"package": "rpm",
|
|
"members": ["rpm-test"],
|
|
},
|
|
"empty-virtual-test": {
|
|
"package": "helm",
|
|
"members": [],
|
|
},
|
|
},
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Write temp config and set env vars BEFORE importing the package
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_tmpdir = tempfile.mkdtemp()
|
|
_config_path = os.path.join(_tmpdir, "remotes.yaml")
|
|
with open(_config_path, "w") as _f:
|
|
yaml.dump(TEST_REMOTES, _f)
|
|
|
|
os.environ.update(
|
|
{
|
|
"CONFIG_PATH": _config_path,
|
|
"MINIO_ENDPOINT": "localhost:9000",
|
|
"MINIO_ACCESS_KEY": "testkey",
|
|
"MINIO_SECRET_KEY": "testsecret",
|
|
"MINIO_BUCKET": "testbucket",
|
|
"REDIS_URL": "redis://localhost:6379/0",
|
|
"DBHOST": "localhost",
|
|
"DBPORT": "5432",
|
|
"DBUSER": "test",
|
|
"DBPASS": "test",
|
|
"DBNAME": "test",
|
|
}
|
|
)
|
|
|
|
# Patch external service connections before the package is imported.
|
|
# These stay active for the whole session (process exits after tests finish).
|
|
_boto3_patch = patch("boto3.client", return_value=MagicMock())
|
|
_redis_patch = patch("redis.from_url", return_value=MagicMock())
|
|
_psycopg2_patch = patch("psycopg2.connect", return_value=MagicMock())
|
|
_boto3_patch.start()
|
|
_redis_patch.start()
|
|
_psycopg2_patch.start()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Shared fixtures
|
|
# ---------------------------------------------------------------------------
|
|
|
|
import pytest # noqa: E402
|
|
from fastapi.testclient import TestClient # noqa: E402
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app():
|
|
from artifactapi.main import app as fastapi_app
|
|
|
|
return fastapi_app
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def client(app):
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def config_path():
|
|
return _config_path
|
|
|
|
|
|
@pytest.fixture
|
|
def test_remotes():
|
|
return TEST_REMOTES
|