<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;
use std::process::Command;

use serde_json::{self, Value as JsonValue};

use error::{Error, Result};
use runner::docker::DockerExporterSpec;
use runner::workspace::Workspace;

// TODO fn: The horror... well, it's not that bad. There isn't a quick win for recursive chown'ing
// a path, so we'll use the `chown` binary as provided by busybox and guarenteed by the Supervisor.
// I'm wincing here right now, honest.
pub fn chown_recursive<P: AsRef<Path>>(path: P, uid: u32, gid: u32) -> Result<()> {
    let mut cmd = Command::new("chown");
    cmd.arg("-R"); // Recursively apply ownership
    cmd.arg(format!("{}:{}", uid, gid));
    cmd.arg(path.as_ref());
    debug!("building chown command, cmd={:?}", &cmd);

    debug!("spawning chown command");
    let mut child = cmd.spawn().map_err(|e| {
        Error::Chown(path.as_ref().to_path_buf(), uid, gid, e)
    })?;
    let exit_status = child.wait().map_err(Error::ChownWait)?;
    debug!("completed chown command, status={:?}", exit_status);
    Ok(())
}

// TODO fn: Here's a sure sign you want more data integrity throughout the system. Most of this
// validation should happen way, way upstream, but that's future refactoring work. Also, if the
// payloads are known structures then serde derive and structs will make better work of things.
// For the moment though, this is validation by hand. Welcome to our cave of shame, folks.

/// Validate integration data in job.
pub fn validate_integrations(workspace: &Workspace) -> Result<()> {
    // Validate project integration
    {
        let prj_integrations = workspace.job.get_project_integrations();
        if prj_integrations.is_empty() {
            // No project integrations, that's cool, we're done!
            return Ok(());
        }

        let prj_integration = prj_integrations.first().unwrap();

        if prj_integration.get_integration_name() != "default" {
            return Err(Error::InvalidIntegrations(format!(
                "integration name '{}' not supported",
                prj_integration.get_integration_name()
            )));
        }
        // TODO fn: use a struct and serde to do heavy lifting
        let opts: JsonValue = match serde_json::from_str(prj_integration.get_body()) {
            Ok(json) => json,
            Err(err) => {
                return Err(Error::InvalidIntegrations(format!(
                    "project integration body does not deserialize as JSON: {:?}",
                    err
                )))
            }
        };
        // Required keys with string values
        for str_key in vec!["docker_hub_repo_name"].iter() {
            match opts.get(str_key) {
                Some(val) => {
                    if val.is_string() {
                        if val.as_str().unwrap().is_empty() {
                            return Err(Error::InvalidIntegrations(format!(
                                "project integration {} value must be a nonempty string",
                                str_key
                            )));
                        }
                    } else {
                        return Err(Error::InvalidIntegrations(format!(
                            "project integration {} value must be a string",
                            str_key
                        )));<commit_msg>Disable integration name check since we removed the db column it was checking<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::Path;
use std::process::Command;

use serde_json::{self, Value as JsonValue};

use error::{Error, Result};
use runner::docker::DockerExporterSpec;
use runner::workspace::Workspace;

// TODO fn: The horror... well, it's not that bad. There isn't a quick win for recursive chown'ing
// a path, so we'll use the `chown` binary as provided by busybox and guarenteed by the Supervisor.
// I'm wincing here right now, honest.
pub fn chown_recursive<P: AsRef<Path>>(path: P, uid: u32, gid: u32) -> Result<()> {
    let mut cmd = Command::new("chown");
    cmd.arg("-R"); // Recursively apply ownership
    cmd.arg(format!("{}:{}", uid, gid));
    cmd.arg(path.as_ref());
    debug!("building chown command, cmd={:?}", &cmd);

    debug!("spawning chown command");
    let mut child = cmd.spawn().map_err(|e| {
        Error::Chown(path.as_ref().to_path_buf(), uid, gid, e)
    })?;
    let exit_status = child.wait().map_err(Error::ChownWait)?;
    debug!("completed chown command, status={:?}", exit_status);
    Ok(())
}

// TODO fn: Here's a sure sign you want more data integrity throughout the system. Most of this
// validation should happen way, way upstream, but that's future refactoring work. Also, if the
// payloads are known structures then serde derive and structs will make better work of things.
// For the moment though, this is validation by hand. Welcome to our cave of shame, folks.

/// Validate integration data in job.
pub fn validate_integrations(workspace: &Workspace) -> Result<()> {
    // Validate project integration
    {
        let prj_integrations = workspace.job.get_project_integrations();
        if prj_integrations.is_empty() {
            // No project integrations, that's cool, we're done!
            return Ok(());
        }

        let prj_integration = prj_integrations.first().unwrap();

        // TODO fn: use a struct and serde to do heavy lifting
        let opts: JsonValue = match serde_json::from_str(prj_integration.get_body()) {
            Ok(json) => json,
            Err(err) => {
                return Err(Error::InvalidIntegrations(format!(
                    "project integration body does not deserialize as JSON: {:?}",
                    err
                )))
            }
        };
        // Required keys with string values
        for str_key in vec!["docker_hub_repo_name"].iter() {
            match opts.get(str_key) {
                Some(val) => {
                    if val.is_string() {
                        if val.as_str().unwrap().is_empty() {
                            return Err(Error::InvalidIntegrations(format!(
                                "project integration {} value must be a nonempty string",
                                str_key
                            )));
                        }
                    } else {
                        return Err(Error::InvalidIntegrations(format!(
                            "project integration {} value must be a string",
                            str_key
                        )));
{'fraction_non_alphanumeric': 0.11392732445364025, 'fraction_numerical': 0.003103582050950472, 'mean_word_length': 2.2660472972972974, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4882366', 'n_tokens_mistral': 2094, 'n_tokens_neox': 2034, 'n_words': 724}