Skip to content

fix: docker pull fallback on linux amd64 for apple silicon #1104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ Yanked: release process issue.
#### IaC

- `ggshield iac scan` now provides three new commands for use as Git hooks:

- `ggshield iac scan pre-commit`
- `ggshield iac scan pre-push`
- `ggshield iac scan pre-receive`
Expand Down Expand Up @@ -635,6 +636,7 @@ Yanked: release process issue.
- New command: `ggshield iac scan all`. This command replaces the now-deprecated `ggshield iac scan`. It scans a directory for IaC vulnerabilities.

- New command: `ggshield iac scan diff`. This command scans a Git repository and inspects changes in IaC vulnerabilities between two points in the history.

- All options from `ggshield iac scan all` are supported: `--ignore-policy`, `--minimum-severity`, `--ignore-path` etc. Execute `ggshield iac scan diff -h` for more details.
- Two new options allow to choose which state to select for the difference: `--ref <GIT-REFERENCE>` and `--staged`.
- The command can be integrated in Git hooks using the `--pre-commit`, `--pre-push`, `--pre-receive` options.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- When scanning a docker image, if no image is found matching the client platform, try to pull the `linux/amd64` image.
34 changes: 32 additions & 2 deletions ggshield/verticals/secret/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,45 @@

Timeout after `timeout` seconds.
"""
command = ["docker", "pull", image_name]
# Base command for docker pull
base_command = ["docker", "pull", image_name]

# Try standard pull first
if _run_docker_command(base_command, timeout):
return

# Fall back to linux/amd64 if no success
amd64_command = base_command + ["--platform=linux/amd64"]
if _run_docker_command(amd64_command, timeout):
return

Check warning on line 302 in ggshield/verticals/secret/docker.py

View check run for this annotation

Codecov / codecov/patch

ggshield/verticals/secret/docker.py#L302

Added line #L302 was not covered by tests

# Raise error if no success
raise UsageError(f'Image "{image_name}" not found')


def _run_docker_command(command: List[str], timeout: int) -> bool:
"""
Run a docker command with timeout and return success status

Args:
command: Docker command to run as a list of strings
timeout: Timeout in seconds

Returns:
True if command succeeded, False if CalledProcessError

Raises:
UnexpectedError: If command times out
"""
try:
subprocess.run(
command,
check=True,
timeout=timeout,
)
return True
except subprocess.CalledProcessError:
raise UsageError(f'Image "{image_name}" not found')
return False
except subprocess.TimeoutExpired:
raise UnexpectedError('Command "{}" timed out'.format(" ".join(command)))

Expand Down
14 changes: 14 additions & 0 deletions tests/unit/verticals/secret/test_scan_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,20 @@ def test_docker_pull_image_timeout(self):
):
docker_pull_image("ggshield-non-existant", DOCKER_TIMEOUT)

def test_docker_pull_image_platform_fallback(self):
with patch(
"subprocess.run", side_effect=subprocess.CalledProcessError(1, cmd=[])
) as call, pytest.raises(
click.UsageError,
match='Image "ggshield-non-existant" not found',
):
docker_pull_image("ggshield-non-existant", DOCKER_TIMEOUT)
call.assert_called_once_with(
["docker", "pull", "ggshield-non-existant", "--platform=linux/amd64"],
check=True,
timeout=DOCKER_TIMEOUT,
)


class TestDockerSave:
TMP_ARCHIVE = Path("/tmp/as/archive.tar")
Expand Down