Add policy fetching from insights api with authorization (#259)

This commit is contained in:
jatin 2023-03-23 09:46:01 +05:30 committed by GitHub
commit 61c2ffb99a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 329 additions and 8 deletions

View file

@ -24,6 +24,11 @@ inputs:
description: "Disable file monitoring"
required: false
default: "false"
policy:
description: "Policy ID to be used from insights website"
required: false
default: ""
branding:
icon: "check-square"
color: "green"

4
dist/post/index.js vendored
View file

@ -61292,8 +61292,8 @@ var cleanup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _
core.error(line);
});
}
var disable_sudo = core.getBooleanInput("disable-sudo");
if (!disable_sudo) {
var disable_sudo = process.env.STATE_disableSudo;
if (disable_sudo !== "true") {
var journalLog = external_child_process_.execSync("sudo journalctl -u agent.service", {
encoding: "utf8",
});

File diff suppressed because one or more lines are too long

72
dist/pre/index.js vendored
View file

@ -69094,6 +69094,59 @@ function isValidEvent() {
return RefKey in process.env && Boolean(process.env[RefKey]);
}
;// CONCATENATED MODULE: ./src/policy-utils.ts
var policy_utils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const API_ENDPOINT = "https://agent.api.stepsecurity.io/v1";
function fetchPolicy(owner, policyName, idToken) {
return policy_utils_awaiter(this, void 0, void 0, function* () {
if (idToken === "") {
throw new Error("[PolicyFetch]: id-token in empty");
}
let policyEndpoint = `${API_ENDPOINT}/github/${owner}/actions/policies/${policyName}`;
let httpClient = new lib.HttpClient();
let headers = {};
headers["Authorization"] = `Bearer ${idToken}`;
headers["Source"] = "github-actions";
let response = yield httpClient.getJson(policyEndpoint, headers);
if (response.statusCode !== 200) {
// policy doesn't exists
switch (response.statusCode) {
case 400:
throw new Error("[PolicyFetch: policy doesn't exists");
case 401:
throw new Error("[PolicyFetch]: supplied id-token can't be used for authentication");
case 403:
throw new Error("[PolicyFetch]: access to policy not allowed");
}
}
return response.result;
});
}
function mergeConfigs(localConfig, remoteConfig) {
if (localConfig.allowed_endpoints === "") {
localConfig.allowed_endpoints = remoteConfig.allowed_endpoints.join(" ");
}
if (remoteConfig.disable_sudo !== undefined) {
localConfig.disable_sudo = remoteConfig.disable_sudo;
}
if (remoteConfig.disable_file_monitoring !== undefined) {
localConfig.disable_file_monitoring = remoteConfig.disable_file_monitoring;
}
if (remoteConfig.egress_policy !== undefined) {
localConfig.egress_policy = remoteConfig.egress_policy;
}
return localConfig;
}
// EXTERNAL MODULE: ./node_modules/@actions/cache/lib/internal/cacheHttpClient.js
var cacheHttpClient = __nccwpck_require__(8245);
// EXTERNAL MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
@ -69123,6 +69176,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
(() => setup_awaiter(void 0, void 0, void 0, function* () {
try {
if (process.platform !== "linux") {
@ -69137,7 +69191,7 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
var env = "agent";
var api_url = `https://${env}.api.stepsecurity.io/v1`;
var web_url = "https://app.stepsecurity.io";
const confg = {
let confg = {
repo: process.env["GITHUB_REPOSITORY"],
run_id: process.env["GITHUB_RUN_ID"],
correlation_id: correlation_id,
@ -69150,6 +69204,22 @@ var setup_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
disable_file_monitoring: lib_core.getBooleanInput("disable-file-monitoring"),
private: github.context.payload.repository.private,
};
let policyName = lib_core.getInput("policy");
if (policyName !== "") {
try {
let idToken = yield lib_core.getIDToken();
let result = yield fetchPolicy(github.context.repo.owner, policyName, idToken);
confg = mergeConfigs(confg, result);
}
catch (err) {
lib_core.info(`[!] ${err}`);
lib_core.setFailed(err);
}
}
external_fs_.appendFileSync(process.env.GITHUB_STATE, `disableSudo=${confg.disable_sudo}${external_os_.EOL}`, {
encoding: "utf8",
});
lib_core.info(`[!] Current Configuration: \n${JSON.stringify(confg)}\n`);
if (confg.egress_policy !== "audit" && confg.egress_policy !== "block") {
lib_core.setFailed("egress-policy must be either audit or block");
}

File diff suppressed because one or more lines are too long

67
package-lock.json generated
View file

@ -30,6 +30,7 @@
"eslint-config-google": "^0.14.0",
"jest": "^29.3.1",
"jest-junit": ">=13.0.0",
"nock": "^13.3.0",
"ts-jest": "^29.0.3",
"typescript": "^4.3.5"
}
@ -5404,6 +5405,12 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
"dev": true
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@ -5465,6 +5472,12 @@
"node": ">=8"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@ -5616,6 +5629,21 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"node_modules/nock": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz",
"integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==",
"dev": true,
"dependencies": {
"debug": "^4.1.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.21",
"propagate": "^2.0.0"
},
"engines": {
"node": ">= 10.13"
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@ -5945,6 +5973,15 @@
"node": ">= 6"
}
},
"node_modules/propagate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@ -10914,6 +10951,12 @@
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
"dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
"dev": true
},
"json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@ -10957,6 +11000,12 @@
"p-locate": "^4.1.0"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@ -11075,6 +11124,18 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"nock": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz",
"integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==",
"dev": true,
"requires": {
"debug": "^4.1.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.21",
"propagate": "^2.0.0"
}
},
"node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@ -11302,6 +11363,12 @@
"sisteransi": "^1.0.5"
}
},
"propagate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
"dev": true
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",

View file

@ -44,6 +44,7 @@
"eslint-config-google": "^0.14.0",
"jest": "^29.3.1",
"jest-junit": ">=13.0.0",
"nock": "^13.3.0",
"ts-jest": "^29.0.3",
"typescript": "^4.3.5"
}

View file

@ -70,8 +70,8 @@ import path from "path";
});
}
var disable_sudo = core.getBooleanInput("disable-sudo");
if (!disable_sudo) {
var disable_sudo = process.env.STATE_disableSudo;
if (disable_sudo !== "true") {
var journalLog = cp.execSync("sudo journalctl -u agent.service", {
encoding: "utf8",
});

23
src/interfaces.ts Normal file
View file

@ -0,0 +1,23 @@
export interface Configuration {
repo: string;
run_id: string;
correlation_id: string;
working_directory: string;
api_url: string;
allowed_endpoints: string;
egress_policy: string;
disable_telemetry: boolean;
disable_sudo: boolean;
disable_file_monitoring: boolean;
private: string;
}
export interface PolicyResponse {
owner?: string;
policyName?: string;
allowed_endpoints?: string[];
disable_sudo?: boolean;
disable_file_monitoring?: boolean;
disable_telemetry?: boolean;
egress_policy?: string;
}

67
src/policy-utils.test.ts Normal file
View file

@ -0,0 +1,67 @@
import nock from "nock";
import { API_ENDPOINT, fetchPolicy, mergeConfigs } from "./policy-utils";
import { Configuration, PolicyResponse } from "./interfaces";
test("success: fetching policy", async () => {
let owner = "h0x0er";
let policyName = "policy1";
let response = {
owner: "h0x0er",
policyName: "policy1",
allowed_endpoints: ["github.com:443"],
egress_policy: "audit",
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
};
const policyScope = nock(`${API_ENDPOINT}`)
.get(`/github/${owner}/actions/policies/${policyName}`)
.reply(200, response);
let idToken = "xyz";
let policy = await fetchPolicy(owner, policyName, idToken);
console.log(policy);
expect(policy).toStrictEqual(response);
});
test("merge configs", async () => {
let localConfig: Configuration = {
repo: "test/repo",
run_id: "xyx",
correlation_id: "aaaaa",
working_directory: "/xyz",
api_url: "xyz",
allowed_endpoints: "",
egress_policy: "audit",
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
private: "true",
};
let policyResponse: PolicyResponse = {
owner: "h0x0er",
policyName: "policy1",
allowed_endpoints: ["github.com:443", "google.com:443"],
egress_policy: "audit",
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
};
let expectedConfiguration: Configuration = {
repo: "test/repo",
run_id: "xyx",
correlation_id: "aaaaa",
working_directory: "/xyz",
api_url: "xyz",
allowed_endpoints: "github.com:443 google.com:443",
egress_policy: "audit",
disable_telemetry: false,
disable_sudo: false,
disable_file_monitoring: false,
private: "true",
};
localConfig = mergeConfigs(localConfig, policyResponse);
expect(localConfig).toStrictEqual(expectedConfiguration);
});

62
src/policy-utils.ts Normal file
View file

@ -0,0 +1,62 @@
import { HttpClient } from "@actions/http-client";
import { PolicyResponse, Configuration } from "./interfaces";
export const API_ENDPOINT = "https://agent.api.stepsecurity.io/v1";
export async function fetchPolicy(
owner: string,
policyName: string,
idToken: string
): Promise<PolicyResponse> {
if (idToken === "") {
throw new Error("[PolicyFetch]: id-token in empty");
}
let policyEndpoint = `${API_ENDPOINT}/github/${owner}/actions/policies/${policyName}`;
let httpClient = new HttpClient();
let headers = {};
headers["Authorization"] = `Bearer ${idToken}`;
headers["Source"] = "github-actions";
let response = await httpClient.getJson<PolicyResponse>(
policyEndpoint,
headers
);
if (response.statusCode !== 200) {
// policy doesn't exists
switch (response.statusCode) {
case 400:
throw new Error("[PolicyFetch: policy doesn't exists");
case 401:
throw new Error("[PolicyFetch]: supplied id-token can't be used for authentication");
case 403:
throw new Error("[PolicyFetch]: access to policy not allowed")
}
}
return response.result;
}
export function mergeConfigs(
localConfig: Configuration,
remoteConfig: PolicyResponse
) {
if (localConfig.allowed_endpoints === "") {
localConfig.allowed_endpoints = remoteConfig.allowed_endpoints.join(" ");
}
if (remoteConfig.disable_sudo !== undefined) {
localConfig.disable_sudo = remoteConfig.disable_sudo;
}
if (remoteConfig.disable_file_monitoring !== undefined) {
localConfig.disable_file_monitoring = remoteConfig.disable_file_monitoring;
}
if (remoteConfig.egress_policy !== undefined) {
localConfig.egress_policy = remoteConfig.egress_policy;
}
return localConfig;
}

View file

@ -17,6 +17,8 @@ import {
CompressionMethod,
isValidEvent,
} from "./cache";
import { Configuration, PolicyResponse } from "./interfaces";
import { fetchPolicy, mergeConfigs } from "./policy-utils";
import {getCacheEntry} from "@actions/cache/lib/internal/cacheHttpClient"
import * as utils from '@actions/cache/lib/internal/cacheUtils'
@ -37,7 +39,7 @@ import * as utils from '@actions/cache/lib/internal/cacheUtils'
var api_url = `https://${env}.api.stepsecurity.io/v1`;
var web_url = "https://app.stepsecurity.io";
const confg = {
let confg: Configuration = {
repo: process.env["GITHUB_REPOSITORY"],
run_id: process.env["GITHUB_RUN_ID"],
correlation_id: correlation_id,
@ -51,6 +53,30 @@ import * as utils from '@actions/cache/lib/internal/cacheUtils'
private: context.payload.repository.private,
};
let policyName = core.getInput("policy");
if (policyName !== "") {
try {
let idToken: string = await core.getIDToken()
let result: PolicyResponse = await fetchPolicy(
context.repo.owner,
policyName,
idToken
);
confg = mergeConfigs(confg, result);
} catch (err) {
core.info(`[!] ${err}`);
core.setFailed(err);
}
}
fs.appendFileSync(
process.env.GITHUB_STATE,
`disableSudo=${confg.disable_sudo}${EOL}`,
{
encoding: "utf8",
}
);
core.info(`[!] Current Configuration: \n${JSON.stringify(confg)}\n`);
if (confg.egress_policy !== "audit" && confg.egress_policy !== "block") {
core.setFailed("egress-policy must be either audit or block");
}