Skip to content
This repository was archived by the owner on Oct 8, 2024. It is now read-only.

Commit 222fb48

Browse files
authored
Merge pull request #6 from github/add-file-feature
Add file feature
2 parents 9fb838b + b888d3d commit 222fb48

File tree

6 files changed

+124
-36
lines changed

6 files changed

+124
-36
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Options:
2020
-cfg, --config <string> location for the config yaml file. Default ".ghec-audit-log" (default: "./.ghec-audit-log")
2121
-p, --pretty prints the json data in a readable format (default: false)
2222
-l, --limit a maximum limit on the number of items retrieved
23+
-f, --file the name of the file where you want to output the result
2324
-c, --cursor <string> if provided, this cursor will be used to query the newest entries from the cursor provided. If not present,
2425
the result will contain all the audit log from the org
2526
-h, --help display help for command

ghec-audit-log-cli.js

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ const YAML = require('yaml');
33
const fs = require('fs');
44
const {graphql} = require('@octokit/graphql');
55
const {requestEntries} = require('./ghec-audit-log-client');
6+
const {validateInput} = require('./ghec-audit-log-utils');
67

7-
//---- Obtain configuration
8+
// Obtain configuration
89
const { program } = require('commander');
910
program.version('1.0.0', '-v, --version', 'Output the current version')
10-
.option('-t, --token <string>', 'the token to access the API (mandatory)')
11-
.option('-o, --org <string>', 'the organization we want to extract the audit log from')
12-
.option('-cfg, --config <string>', 'location for the config yaml file. Default ".ghec-audit-log"', './.ghec-audit-log')
13-
.option('-p, --pretty', 'prints the json data in a readable format', false)
14-
.option('-l, --limit <number>', 'a maximum limit on the number of items retrieved')
15-
.option('-c, --cursor <string>', 'if provided, this cursor will be used to query the newest entries from the cursor provided. If not present,\n' +
16-
' the result will contain all the audit log from the org');
11+
.option('-t, --token <string>', 'the token to access the API (mandatory)')
12+
.option('-o, --org <string>', 'the organization we want to extract the audit log from')
13+
.option('-cfg, --config <string>', 'location for the config yaml file. Default ".ghec-audit-log"', './.ghec-audit-log')
14+
.option('-p, --pretty', 'prints the json data in a readable format', false)
15+
.option('-l, --limit <number>', 'a maximum limit on the number of items retrieved')
16+
.option('-f, --file <string>', 'the output file where the result should be printed')
17+
.option('-c, --cursor <string>', 'if provided, this cursor will be used to query the newest entries from the cursor provided. If not present, the result will contain all the audit log from the org');
1718

1819
program.parse(process.argv);
1920

@@ -22,26 +23,12 @@ let config = {};
2223
try {
2324
config = YAML.parse(fs.readFileSync(configLocation, 'utf8'));
2425
} catch(e) {
25-
console.log(`${configLocation} file missing. Path parameters will apply`);
26+
console.log(`${configLocation} file missing. Path parameters will apply`)
2627
}
2728

28-
const cursor = program.cursor || null;
29-
const pretty = program.pretty || false;
30-
const limit = program.limit;
31-
const token = program.token || config.token;
32-
const org = program.org || config.org;
33-
3429
//TODO idea: maybe add support for other formats like PUTVAL to forward the data in an easier way
30+
const {cursor, pretty, limit, token, org, outputFile} = validateInput(program, config)
3531

36-
//---- Run validation
37-
if (!token) {
38-
throw new Error("Token must be provided in the configuration or as a --token argument");
39-
}
40-
if (!org) {
41-
throw new Error("Organization must be provided in the configuration or as a --org argument");
42-
}
43-
44-
//---- Helper function
4532
/**
4633
* Function containing all the queries
4734
*/
@@ -60,23 +47,29 @@ async function queryAuditLog() {
6047
if(newestCursorId) fs.writeFileSync('.last-cursor-update', newestCursorId);
6148

6249
// Return the data
63-
if (pretty) {
50+
if (pretty === true) {
6451
return JSON.stringify(entries, null, 4);
6552
} else {
6653
return JSON.stringify(entries);
6754
}
6855
}
6956

7057

71-
//---- Execute the request and print the result
58+
// Execute the request and print the result
7259
const graphqlWithAuth = graphql.defaults({
7360
headers: {
7461
authorization: `token ${token}`,
7562
},
7663
});
7764
queryAuditLog()
78-
.then((data) => console.log(data))
79-
.catch((err) => {
80-
console.error(err);
81-
process.exit(1);
82-
});
65+
.then((data) => {
66+
if(outputFile){
67+
fs.writeFileSync(outputFile, data);
68+
} else {
69+
console.log(data)
70+
}
71+
})
72+
.catch((err) => {
73+
console.error(err);
74+
process.exit(1);
75+
});

ghec-audit-log-utils.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const validate = require('validate.js')
2+
const fs = require('fs')
3+
const path = require('path')
4+
5+
function validateInput (program, config) {
6+
const parsed = {
7+
cursor: program.cursor || null,
8+
pretty: program.pretty || false,
9+
limit: program.limit || null,
10+
token: program.token || config.token,
11+
org: program.org || config.org,
12+
outputFile: program.file
13+
}
14+
15+
// Validate correctness
16+
const alphanumericRegex = /^[a-z0-9]+$/i
17+
const base64Regex = '(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)';
18+
const orgRegex = /^[a-z\d]+(?:-?[a-z\d]+)*$/i
19+
const constraints = {
20+
cursor: {
21+
type: 'string',
22+
presence: false,
23+
format: base64Regex
24+
},
25+
pretty: {
26+
type: 'boolean',
27+
presence: true,
28+
},
29+
limit: {
30+
presence: false,
31+
numericality: {
32+
onlyInteger: true,
33+
greaterThan: 0,
34+
}
35+
},
36+
token: {
37+
type: 'string',
38+
presence: { allowEmpty: false },
39+
length: {
40+
is: 40
41+
},
42+
format: alphanumericRegex
43+
},
44+
org: {
45+
type: 'string',
46+
presence: { allowEmpty: false },
47+
length: {
48+
maximum: 39,
49+
minimum: 1
50+
},
51+
format: orgRegex
52+
},
53+
outputFile: {
54+
type: 'string',
55+
presence: false,
56+
}
57+
}
58+
59+
//Verify validation
60+
const validation = validate(parsed, constraints)
61+
if(!validate.isEmpty(validation)) {
62+
throw new Error(JSON.stringify(validation))
63+
}
64+
65+
//Check that we can write into that file
66+
if(parsed.outputFile){
67+
try {
68+
fs.openSync(parsed.outputFile, 'w')
69+
}catch (e) {
70+
throw new Error(`The output file ${parsed.outputFile} cannot be written or the path does not exist. ${e.message}`)
71+
}
72+
}
73+
//Check that if we are in GitHub actions the file is expected to be within the workspace
74+
if(process.env.GITHUB_ACTIONS) {
75+
const filePath = path.join(process.env.GITHUB_WORKSPACE, parsed.outputFile)
76+
const {dir} = path.parse(filePath)
77+
78+
if (dir.indexOf(process.env.GITHUB_WORKSPACE) < 0) {
79+
throw new Error(`${parsed.outputFile} is not allowed. The directory should be within ${process.env.GITHUB_WORKSPACE}`)
80+
}
81+
}
82+
83+
return parsed
84+
}
85+
86+
module.exports = {
87+
validateInput
88+
}

package-lock.json

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"dependencies": {
2828
"@octokit/graphql": "^4.3.1",
2929
"commander": "^5.1.0",
30+
"validate.js": "^0.13.1",
3031
"yaml": "^1.9.2"
3132
},
3233
"bin": {

workflow/node-workflow.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
- run: |
2222
if [ -z "$LAST_CURSOR" ]; then
2323
echo "FIRST TIME RUNNING AUDIT LOG POLL"
24-
npm start -- --pretty --token ${{secrets.AUDIT_LOG_TOKEN}} --org ${{secrets.ORG_NAME}} >> audit-log-output.json
24+
npm start -- --pretty --token ${{secrets.AUDIT_LOG_TOKEN}} --org ${{secrets.ORG_NAME}} --file 'audit-log-output.json'
2525
else
2626
echo "RUNNING AUDIT LOG POLL FROM $LAST_CURSOR"
27-
npm start -- --pretty --token ${{secrets.AUDIT_LOG_TOKEN}} --org ${{secrets.ORG_NAME}} --cursor $LAST_CURSOR >> audit-log-output.json
27+
npm start -- --pretty --token ${{secrets.AUDIT_LOG_TOKEN}} --org ${{secrets.ORG_NAME}} --file 'audit-log-output.json'
2828
fi
2929
# Cat the output. Optionally send it somewhere else
3030
- run: cat audit-log-output.json

0 commit comments

Comments
 (0)