Skip to content

Commit

Permalink
feat: support docker_image (#113)
Browse files Browse the repository at this point in the history
* feat: support docker_image

* test: add docker_image test case

* test: fix test failed when git default branch set `main`

* Minor tweaks

---------

Co-authored-by: j178 <[email protected]>
  • Loading branch information
bxb100 and j178 authored Nov 25, 2024
1 parent df23edb commit b3619ba
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/languages/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl Docker {
Ok(Cow::Borrowed(path))
}

async fn docker_cmd() -> Result<Cmd> {
pub(crate) async fn docker_cmd() -> Result<Cmd> {
let mut command = Cmd::new("docker", "run container");
command.arg("run").arg("--rm");

Expand Down Expand Up @@ -212,7 +212,7 @@ impl LanguageImpl for Docker {
.args(&cmds[1..])
.args(hook_args.as_ref())
.args(batch)
.stderr(std::process::Stdio::inherit())
.check(false)
.envs(env_vars.as_ref());

let mut output = cmd.output().await?;
Expand Down
74 changes: 74 additions & 0 deletions src/languages/docker_image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::collections::HashMap;
use std::sync::Arc;

use crate::hook::Hook;
use crate::languages::docker::Docker;
use crate::languages::{LanguageImpl, DEFAULT_VERSION};
use crate::run::run_by_batch;

#[derive(Debug, Copy, Clone)]
pub struct DockerImage;

impl LanguageImpl for DockerImage {
fn default_version(&self) -> &str {
DEFAULT_VERSION
}

fn environment_dir(&self) -> Option<&str> {
None
}

async fn install(&self, _: &Hook) -> anyhow::Result<()> {
Ok(())
}

async fn check_health(&self) -> anyhow::Result<()> {
todo!()
}

async fn run(
&self,
hook: &Hook,
filenames: &[&String],
env_vars: Arc<HashMap<&'static str, String>>,
) -> anyhow::Result<(i32, Vec<u8>)> {
let cmds = shlex::split(&hook.entry).ok_or(anyhow::anyhow!("Failed to parse entry"))?;

let cmds = Arc::new(cmds);
let hook_args = Arc::new(hook.args.clone());

let run = move |batch: Vec<String>| {
let cmds = cmds.clone();
let hook_args = hook_args.clone();
let env_vars = env_vars.clone();

async move {
let mut cmd = Docker::docker_cmd().await?;
let cmd = cmd
.args(&cmds[..])
.args(hook_args.as_ref())
.args(batch)
.check(false)
.envs(env_vars.as_ref());

let mut output = cmd.output().await?;
output.stdout.extend(output.stderr);
let code = output.status.code().unwrap_or(1);
anyhow::Ok((code, output.stdout))
}
};

let results = run_by_batch(hook, filenames, run).await?;

// Collect results
let mut combined_status = 0;
let mut combined_output = Vec::new();

for (code, output) in results {
combined_status |= code;
combined_output.extend(output);
}

Ok((combined_status, combined_output))
}
}
7 changes: 7 additions & 0 deletions src/languages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::config::Language;
use crate::hook::Hook;

mod docker;
mod docker_image;
mod fail;
mod node;
mod python;
Expand All @@ -17,6 +18,7 @@ static NODE: node::Node = node::Node;
static SYSTEM: system::System = system::System;
static FAIL: fail::Fail = fail::Fail;
static DOCKER: docker::Docker = docker::Docker;
static DOCKER_IMAGE: docker_image::DockerImage = docker_image::DockerImage;

pub const DEFAULT_VERSION: &str = "default";

Expand All @@ -41,6 +43,7 @@ impl Language {
Self::System => SYSTEM.default_version(),
Self::Fail => FAIL.default_version(),
Self::Docker => DOCKER.default_version(),
Self::DockerImage => DOCKER_IMAGE.default_version(),
_ => todo!(),
}
}
Expand All @@ -52,6 +55,7 @@ impl Language {
Self::System => SYSTEM.environment_dir(),
Self::Fail => FAIL.environment_dir(),
Self::Docker => DOCKER.environment_dir(),
Self::DockerImage => DOCKER_IMAGE.environment_dir(),
_ => todo!(),
}
}
Expand All @@ -63,6 +67,7 @@ impl Language {
Self::System => SYSTEM.install(hook).await,
Self::Fail => FAIL.install(hook).await,
Self::Docker => DOCKER.install(hook).await,
Self::DockerImage => DOCKER_IMAGE.install(hook).await,
_ => todo!(),
}
}
Expand All @@ -74,6 +79,7 @@ impl Language {
Self::System => SYSTEM.check_health().await,
Self::Fail => FAIL.check_health().await,
Self::Docker => DOCKER.check_health().await,
Self::DockerImage => DOCKER_IMAGE.check_health().await,
_ => todo!(),
}
}
Expand All @@ -90,6 +96,7 @@ impl Language {
Self::System => SYSTEM.run(hook, filenames, env_vars).await,
Self::Fail => FAIL.run(hook, filenames, env_vars).await,
Self::Docker => DOCKER.run(hook, filenames, env_vars).await,
Self::DockerImage => DOCKER_IMAGE.run(hook, filenames, env_vars).await,
_ => todo!(),
}
}
Expand Down
1 change: 0 additions & 1 deletion src/languages/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ impl LanguageImpl for System {
.args(&cmds[1..])
.args(hook_args.as_ref())
.args(batch)
.stderr(std::process::Stdio::inherit())
.envs(env_vars.as_ref())
.check(false)
.output()
Expand Down
3 changes: 2 additions & 1 deletion tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ impl TestContext {
pub fn init_project(&self) {
Command::new("git")
.arg("init")
.arg("--initial-branch=master")
.current_dir(&self.temp_dir)
.assert()
.success();
Expand Down Expand Up @@ -247,7 +248,7 @@ pub const INSTA_FILTERS: &[(&str, &str)] = &[
"Caused by: No such file or directory (os error 2)",
),
// Time seconds
(r"(\d+\.)?\d+s", "[TIME]"),
(r"(\d+\.)?\d+(ms|s)", "[TIME]"),
];

#[allow(unused_macros)]
Expand Down
4 changes: 4 additions & 0 deletions tests/languages/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ fn docker() {
hooks:
- id: hello-world
entry: "echo Hello, world!"
verbose: true
always_run: true
"#});

Expand All @@ -25,6 +26,9 @@ fn docker() {
Cloning https://github.com/j178/pre-commit-docker-hooks@master
Installing environment for https://github.com/j178/pre-commit-docker-hooks@master
Hello World..............................................................Passed
- hook id: hello-world
- duration: [TIME]
Hello, world! .pre-commit-config.yaml
----- stderr -----
"#);
Expand Down
80 changes: 80 additions & 0 deletions tests/languages/docker_image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use anyhow::Result;
use assert_cmd::Command;
use assert_fs::fixture::{FileWriteStr, PathChild};

use crate::common::{cmd_snapshot, TestContext};

#[test]
fn docker_image() -> Result<()> {
let context = TestContext::new();
context.init_project();

let cwd = context.workdir();
// Test suit from https://github.com/super-linter/super-linter/tree/main/test/linters/gitleaks/bad
cwd.child("gitleaks_bad_01.txt")
.write_str(indoc::indoc! {r"
aws_access_key_id = AROA47DSWDEZA3RQASWB
aws_secret_access_key = wQwdsZDiWg4UA5ngO0OSI2TkM4kkYxF6d2S1aYWM
"})?;

Command::new("docker")
.args(["pull", "zricethezav/gitleaks:v8.21.2"])
.assert()
.success();

context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: local
hooks:
- id: gitleaks-docker
name: Detect hardcoded secrets
language: docker_image
entry: zricethezav/gitleaks:v8.21.2 git --pre-commit --redact --staged --verbose
pass_filenames: false
"});
context.git_add(".");

let filters = context
.filters()
.into_iter()
.chain([(r"\d\d?:\d\d(AM|PM)", "[TIME]")])
.collect::<Vec<_>>();

cmd_snapshot!(filters, context.run(), @r#"
success: false
exit_code: 1
----- stdout -----
Detect hardcoded secrets.................................................Failed
- hook id: gitleaks-docker
- exit code: 1
Finding: aws_access_key_id = REDACTED
Secret: REDACTED
RuleID: generic-api-key
Entropy: 3.521928
File: gitleaks_bad_01.txt
Line: 1
Fingerprint: gitleaks_bad_01.txt:generic-api-key:1
Finding: aws_secret_access_key = REDACTED
Secret: REDACTED
RuleID: generic-api-key
Entropy: 4.703056
File: gitleaks_bad_01.txt
Line: 2
Fingerprint: gitleaks_bad_01.txt:generic-api-key:2
│╲
│ ○
○ ░
░ gitleaks
[TIME] INF 1 commits scanned.
[TIME] INF scan completed in [TIME]
[TIME] WRN leaks found: 2
----- stderr -----
"#);
Ok(())
}
2 changes: 2 additions & 0 deletions tests/languages/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ mod common;

#[cfg(all(feature = "docker", target_os = "linux"))]
mod docker;
#[cfg(all(feature = "docker", target_os = "linux"))]
mod docker_image;
mod fail;

0 comments on commit b3619ba

Please sign in to comment.