use crate::candidate_object::parse_object_id;
use crate::candidate_prediction::CandidateRequest;
use crate::config_schema::PolicyConfig;
use crate::child_environment::environment_value;
use crate::diagnostics::EngineFailureCode;
use crate::policy_checks::shipped_checks;
use crate::policy_content::LifecycleContent;
use crate::policy_engine::{StageEnd, StageRequest, pass_exit_code};
use crate::policy_events::PolicyEvent;
use crate::policy_pass::run_policy_pass;
use crate::policy_trigger::Trigger;
use crate::repository_facts::git_facts;
use crate::scanner_selection::RULES_VARIABLE;
use crate::wrapper_controls::Controls;
use std::ffi::OsString;
use std::path::Path;
pub const POST_COMMIT_BLOCKED_EXIT_CODE: i32 = 2;
#[derive(Clone, Debug)]
pub struct PostCommitRequest<'request> {
pub real_git: &'request Path,
pub landed_oid: &'request str,
pub arguments: &'request [OsString],
pub global_prefix: &'request [OsString],
pub overlay: &'request [(OsString, OsString)],
pub environment: &'request [(OsString, OsString)],
pub config: PolicyConfig,
pub controls: Controls,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PostCommitGate {
pub oid: String,
pub events: Vec<PolicyEvent>,
pub blocked: bool,
}
pub fn run_post_commit_gate(request: &PostCommitRequest) -> PostCommitGate {
let oid = request.landed_oid.to_owned();
let (mut events, end): (Vec<PolicyEvent>, StageEnd) =
match parse_object_id(request.landed_oid.as_bytes()) {
Some(commit) => run_staged_gate(request, commit),
None => (
vec![PolicyEvent::EngineFailure {
code: EngineFailureCode::ContentUnavailable,
hint: crate::policy_events::EngineFailureHint::OfCode,
message: format!("landed commit {} is not an object name", request.landed_oid),
trigger: Some(Trigger::PostCommit),
policy: None,
path: None,
}],
StageEnd::Failed,
),
};
let blocked = pass_exit_code(events.as_slice(), end) != 0;
if blocked {
events.push(PolicyEvent::CommitLanded { oid: oid.clone() });
}
return PostCommitGate {
oid,
events,
blocked,
};
}
fn run_staged_gate(
request: &PostCommitRequest,
commit: crate::candidate_object::ObjectId,
) -> (Vec<PolicyEvent>, StageEnd) {
let facts = git_facts(request.real_git, request.global_prefix, request.overlay);
let mut checks = shipped_checks(
facts,
request.arguments.to_vec(),
LifecycleContent::Requested(CandidateRequest::Landed(commit)),
Vec::new(),
);
checks.scanner_settings.options = request.config.forbidden_strings.clone();
checks.markdown.options = request.config.markdown_autofix.clone();
checks.scanner_settings.rules_variable = environment_value(request.environment, RULES_VARIABLE);
let stage: StageRequest = StageRequest {
trigger: Trigger::PostCommit,
config: request.config.clone(),
controls: request.controls.clone(),
selected: Vec::new(),
};
let pass = run_policy_pass(&stage, &mut checks);
return (pass.events, pass.end);
}
#[cfg(test)]
#[path = "post_commit_tests.rs"]
mod tests;