Publish curated ITWorx_MCP_Hub source from ae713b53e32933192b7446ac25fd6394e69eb133
This commit is contained in:
1 parent
faa53707b9
commit
0086cafc87
4 files changed
+167
-4
No files matched your search
@@ -1,3 +1,3 @@
|
|||||||
# Public source export
|
# Public source export
|
||||||
|
|
||||||
This source snapshot was generated from the private canonical repository at revision `535009426b1f754478673ad9789b16e2c047a32e`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
|
This source snapshot was generated from the private canonical repository at revision `ae713b53e32933192b7446ac25fd6394e69eb133`. It contains no private Git history or operational evidence. Changes are published from the canonical repository.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"sourceRevision": "535009426b1f754478673ad9789b16e2c047a32e",
|
"sourceRevision": "ae713b53e32933192b7446ac25fd6394e69eb133",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": ".dockerignore",
|
"path": ".dockerignore",
|
||||||
@@ -3379,8 +3379,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "tests/test_mcp_hub_release_images.py",
|
"path": "tests/test_mcp_hub_release_images.py",
|
||||||
"sha256": "38cefc6b3d12f8c197ae522c5bd6ecc9e20407bb3be2dca7fe593a87229eecca",
|
"sha256": "d485996a59dcadd9b974245aaee8f0ab3caee75c535d341422de6b213eee92e0",
|
||||||
"bytes": 31898
|
"bytes": 32010
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "tests/test_mcp_workflow_prompts.py",
|
"path": "tests/test_mcp_workflow_prompts.py",
|
||||||
@@ -3462,6 +3462,11 @@
|
|||||||
"sha256": "3a3a6674c9e3146827cc34aa493e0445505067b6e90d5618c3552c7dc2861118",
|
"sha256": "3a3a6674c9e3146827cc34aa493e0445505067b6e90d5618c3552c7dc2861118",
|
||||||
"bytes": 3902
|
"bytes": 3902
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "tests/test_scanner_private_files.py",
|
||||||
|
"sha256": "772b87fafb5a877a32234ab10b6ed418445575ac9dc0e13380491d294c55330c",
|
||||||
|
"bytes": 5048
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "tests/test_stitch_connector.py",
|
"path": "tests/test_stitch_connector.py",
|
||||||
"sha256": "c34cd2dc20721052dc63a15dc763ecc9b4f1adaef1d6ec2d5189adff9161c269",
|
"sha256": "c34cd2dc20721052dc63a15dc763ecc9b4f1adaef1d6ec2d5189adff9161c269",
|
||||||
|
|||||||
@@ -707,6 +707,7 @@ def test_scanner_stdout_bound_does_not_cap_or_capture_cache_files(tmp_path: Path
|
|||||||
def fake_scanner(command: list[str], **kwargs: object) -> subprocess.Popen[bytes]:
|
def fake_scanner(command: list[str], **kwargs: object) -> subprocess.Popen[bytes]:
|
||||||
assert "preexec_fn" not in kwargs
|
assert "preexec_fn" not in kwargs
|
||||||
assert kwargs.get("stdout") == subprocess.PIPE
|
assert kwargs.get("stdout") == subprocess.PIPE
|
||||||
|
assert kwargs.get("umask") == 0o077
|
||||||
code = (
|
code = (
|
||||||
"from pathlib import Path; import os; "
|
"from pathlib import Path; import os; "
|
||||||
"Path('cache.bin').write_bytes(b'x' * (3 * 1024 * 1024)); "
|
"Path('cache.bin').write_bytes(b'x' * (3 * 1024 * 1024)); "
|
||||||
@@ -728,6 +729,7 @@ def test_scanner_stdout_bound_does_not_cap_or_capture_cache_files(tmp_path: Path
|
|||||||
|
|
||||||
assert output == b'{"complete":true}'
|
assert output == b'{"complete":true}'
|
||||||
assert (tmp_path / "cache.bin").stat().st_size == 3 * 1024 * 1024
|
assert (tmp_path / "cache.bin").stat().st_size == 3 * 1024 * 1024
|
||||||
|
assert (tmp_path / "cache.bin").stat().st_mode & 0o777 == 0o600
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from scripts import build_mcp_hub_release_images as producer
|
||||||
|
|
||||||
|
|
||||||
|
def test_database_download_child_has_private_umask_without_changing_other_stages(tmp_path):
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def runner(command, **kwargs):
|
||||||
|
calls.append(kwargs)
|
||||||
|
return subprocess.CompletedProcess(command, 0)
|
||||||
|
|
||||||
|
for stage in ("trivy_db_download", "compose_local_build"):
|
||||||
|
producer._execute(["fixture"], env={}, cwd=tmp_path, timeout=1, stage=stage, runner=runner)
|
||||||
|
assert calls[0]["umask"] == 0o077
|
||||||
|
assert "umask" not in calls[1]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"fault",
|
||||||
|
[
|
||||||
|
None,
|
||||||
|
"owner",
|
||||||
|
"symlink",
|
||||||
|
"hardlink",
|
||||||
|
"oversize",
|
||||||
|
"parent",
|
||||||
|
"db_link",
|
||||||
|
"swap",
|
||||||
|
"parent_swap",
|
||||||
|
"after_swap",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_db_metadata_adapter_restricts_only_owned_anchored_inode(monkeypatch, fault):
|
||||||
|
def info(inode, mode, **extra):
|
||||||
|
fields = dict(
|
||||||
|
st_dev=1, st_ino=inode, st_mode=mode, st_uid=123, st_nlink=1, st_size=16, st_mtime_ns=1
|
||||||
|
)
|
||||||
|
fields.update(extra)
|
||||||
|
return SimpleNamespace(**fields)
|
||||||
|
|
||||||
|
parent = info(1, stat.S_IFDIR | (0o755 if fault == "parent" else 0o700))
|
||||||
|
db = info(2, stat.S_IFDIR | 0o755)
|
||||||
|
metadata = info(3, stat.S_IFREG | 0o644)
|
||||||
|
if fault == "owner":
|
||||||
|
metadata.st_uid = 999
|
||||||
|
if fault == "symlink":
|
||||||
|
metadata.st_mode = stat.S_IFLNK | 0o644
|
||||||
|
if fault == "hardlink":
|
||||||
|
metadata.st_nlink = 2
|
||||||
|
if fault == "oversize":
|
||||||
|
metadata.st_size = 65537
|
||||||
|
restricted = []
|
||||||
|
closed = []
|
||||||
|
opens = []
|
||||||
|
successful = []
|
||||||
|
cache = SimpleNamespace(lstat=lambda: parent)
|
||||||
|
|
||||||
|
def open_file(path, flags, *, dir_fd=None):
|
||||||
|
opens.append((path, dir_fd))
|
||||||
|
assert flags & 0x20000
|
||||||
|
if path is cache:
|
||||||
|
successful.append(10)
|
||||||
|
return 10
|
||||||
|
if path == "db":
|
||||||
|
assert dir_fd == 10
|
||||||
|
if fault == "db_link":
|
||||||
|
raise OSError("fixture-private-value")
|
||||||
|
successful.append(11)
|
||||||
|
return 11
|
||||||
|
assert path == "metadata.json" and dir_fd == 11
|
||||||
|
successful.append(12)
|
||||||
|
return 12
|
||||||
|
|
||||||
|
def fstat(fd):
|
||||||
|
if fd == 10:
|
||||||
|
return parent
|
||||||
|
if fd == 11:
|
||||||
|
return db
|
||||||
|
if fault == "swap":
|
||||||
|
return info(4, metadata.st_mode)
|
||||||
|
return SimpleNamespace(**vars(metadata))
|
||||||
|
|
||||||
|
def inspect(path, *, dir_fd, follow_symlinks):
|
||||||
|
assert follow_symlinks is False
|
||||||
|
if path == "db":
|
||||||
|
assert dir_fd == 10
|
||||||
|
return info(4, db.st_mode) if fault == "parent_swap" else db
|
||||||
|
assert path == "metadata.json" and dir_fd == 11
|
||||||
|
return info(4, metadata.st_mode) if fault == "after_swap" and restricted else metadata
|
||||||
|
|
||||||
|
def restrict(fd, mode):
|
||||||
|
assert fd == 12 and mode == 0o600
|
||||||
|
restricted.append((fd, mode))
|
||||||
|
metadata.st_mode = stat.S_IFREG | 0o600
|
||||||
|
|
||||||
|
monkeypatch.setattr(producer.platform, "system", lambda: "Linux")
|
||||||
|
monkeypatch.setattr(producer, "_effective_uid", lambda: 123)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
producer,
|
||||||
|
"os",
|
||||||
|
SimpleNamespace(
|
||||||
|
O_RDONLY=os.O_RDONLY,
|
||||||
|
O_DIRECTORY=0x10000,
|
||||||
|
O_NOFOLLOW=0x20000,
|
||||||
|
open=open_file,
|
||||||
|
fstat=fstat,
|
||||||
|
stat=inspect,
|
||||||
|
fchmod=restrict,
|
||||||
|
close=closed.append,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if fault:
|
||||||
|
with pytest.raises(producer.BuildRejected) as error:
|
||||||
|
producer._private_db_metadata(cache)
|
||||||
|
assert "fixture-private-value" not in str(error.value)
|
||||||
|
if fault != "after_swap":
|
||||||
|
assert restricted == []
|
||||||
|
else:
|
||||||
|
producer._private_db_metadata(cache)
|
||||||
|
assert restricted == [(12, 0o600)]
|
||||||
|
assert closed == list(reversed(successful))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(os.name != "posix", reason="file-descriptor permission adapter requires Linux")
|
||||||
|
def test_explicit_upstream_chmod_is_restricted_before_strict_json_reader(tmp_path):
|
||||||
|
cache = tmp_path / "cache"
|
||||||
|
db = cache / "db"
|
||||||
|
db.mkdir(parents=True)
|
||||||
|
cache.chmod(0o700)
|
||||||
|
db.chmod(0o755)
|
||||||
|
metadata = db / "metadata.json"
|
||||||
|
metadata.write_text('{"Version":2}')
|
||||||
|
metadata.chmod(0o644)
|
||||||
|
with pytest.raises(producer.BuildRejected, match="not private and bounded"):
|
||||||
|
producer._json_file(metadata, maximum=64 * 1024)
|
||||||
|
producer._private_db_metadata(cache)
|
||||||
|
assert metadata.stat().st_mode & 0o777 == 0o600
|
||||||
|
assert producer._json_file(metadata, maximum=64 * 1024) == {"Version": 2}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(os.name != "posix", reason="kernel umask requires Linux")
|
||||||
|
def test_kernel_download_child_creates_private_files(tmp_path):
|
||||||
|
command = [
|
||||||
|
sys.executable,
|
||||||
|
"-c",
|
||||||
|
"from pathlib import Path; Path('metadata.json').write_text('{}')",
|
||||||
|
]
|
||||||
|
producer._execute(command, env=os.environ, cwd=tmp_path, timeout=10, stage="trivy_db_download")
|
||||||
|
assert (tmp_path / "metadata.json").stat().st_mode & 0o777 == 0o600
|
||||||
Reference in new issue
Block a user