* For generic secret arguments, from-literal will be parsed into from-file * removed export * review comments fix * refractor * refractor * Test cases * TestCases in Typescript * Undoing package-lock.json * Removing Tests from lib * New Test cases * Bug fix and test cases * Bug fix and test cases * Bug fix and test cases Co-authored-by: rgsubh <rgsubh@github.com> Co-authored-by: rgsubh <rgsubh@github.com>
This commit is contained in:
Родитель
726f54ce5c
Коммит
05de697464
|
@ -0,0 +1,17 @@
|
|||
name: "build-test"
|
||||
on: # rebuild any PRs and main branch changes
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'releases/*'
|
||||
|
||||
jobs:
|
||||
build: # make sure build/ci works properly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- run: |
|
||||
npm install
|
||||
npm build
|
||||
npm test
|
|
@ -24,6 +24,9 @@ bld/
|
|||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
|
@ -326,4 +329,4 @@ ASALocalRun/
|
|||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
.mfractor/
|
|
@ -0,0 +1,173 @@
|
|||
import { fromLiteralsToFromFile } from "../src/run"
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { mocked } from 'ts-jest/utils'
|
||||
|
||||
const fileUtility = mocked(fs, true);
|
||||
|
||||
beforeAll(() => {
|
||||
process.env['RUNNER_TEMP'] = '/home/runner/work/_temp';
|
||||
})
|
||||
|
||||
test('Literal converted to file', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key1");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key1=value")).toBe('--from-file=' + filePath);
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value");
|
||||
})
|
||||
|
||||
test('Multiple literal converted to file', () => {
|
||||
var filePath1 = path.join(process.env['RUNNER_TEMP'], "key1");
|
||||
var filePath2 = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key1=value1 --from-literal=key2=value2")).toBe('--from-file=' + filePath1 + ' --from-file=' + filePath2);
|
||||
expect(fileUtility.writeFileSync.mock.calls).toEqual([
|
||||
[filePath1, "value1"],
|
||||
[filePath2, "value2"]
|
||||
])
|
||||
})
|
||||
|
||||
test('File and other argument maintained maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath --otherArgument=value")).toBe('--from-file=./filepath --otherArgument=value')
|
||||
})
|
||||
|
||||
test('File and other argument maintained with trailing spaces maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath --otherArgument=value "))
|
||||
.toBe('--from-file=./filepath --otherArgument=value')
|
||||
})
|
||||
|
||||
test('File and other argument maintained with trailing spaces maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath 00 --otherArgument=value "))
|
||||
.toBe('--from-file=./filepath 00 --otherArgument=value')
|
||||
})
|
||||
|
||||
test('File and other argument maintained with trailing spaces maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath 00 --otherArgument=\"value 0\" --otherArgument=value "))
|
||||
.toBe('--from-file=./filepath 00 --otherArgument=\"value 0\" --otherArgument=value')
|
||||
})
|
||||
|
||||
test('File and other argument maintained maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath --otherArgument=\"value \""))
|
||||
.toBe('--from-file=./filepath --otherArgument=\"value \"')
|
||||
})
|
||||
|
||||
test('File maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--from-file=./filepath")).toBe('--from-file=./filepath')
|
||||
})
|
||||
|
||||
test('Any other argument maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--otherArgument=value")).toBe('--otherArgument=value')
|
||||
})
|
||||
|
||||
test('Any other arguments maintained as-is', () => {
|
||||
expect(fromLiteralsToFromFile("--otherArgument=value --otherArgument=value")).toBe('--otherArgument=value --otherArgument=value')
|
||||
})
|
||||
|
||||
test('Invalid case, no value for secret', () => {
|
||||
expect(() => fromLiteralsToFromFile("--from-literal=key")).toThrow(Error);
|
||||
})
|
||||
|
||||
test('Multiple commnads combined', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=value --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value");
|
||||
})
|
||||
|
||||
test('In-valid trailing space in secret is igonered', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=value --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value");
|
||||
})
|
||||
|
||||
test('Missplaced values ignored', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=value 0 --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value");
|
||||
})
|
||||
|
||||
test('Valid Trailing space in secret', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=\"value 0\" --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value 0");
|
||||
})
|
||||
|
||||
test('Valid space in secret Case1', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=\"value 023\" --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value 023");
|
||||
})
|
||||
|
||||
test('Valid space in secret Case2', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=\" Value 023\" --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, " Value 023");
|
||||
})
|
||||
|
||||
test('Valid " Case1', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=value\"ksk --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "value\"ksk");
|
||||
})
|
||||
|
||||
test('Valid " Case2', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=\"valueksk --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "\"valueksk");
|
||||
})
|
||||
|
||||
test('Valid " Case3', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key2");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key2=valueksk\" --from-file=./filepath --otherArgument=value"))
|
||||
.toBe('--from-file=' + filePath + ' --from-file=./filepath --otherArgument=value');
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "valueksk\"");
|
||||
})
|
||||
|
||||
test('No separator ', () => {
|
||||
expect(fromLiteralsToFromFile("test=this")).toBe('test=this')
|
||||
})
|
||||
|
||||
test('Special characters & in value', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key3");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key3=hello&world")).toBe('--from-file=' + filePath);
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "hello&world");
|
||||
})
|
||||
|
||||
test('Special characters # in value', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key4");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key4=hello#world")).toBe('--from-file=' + filePath);
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "hello#world");
|
||||
})
|
||||
|
||||
test('Special characters = in value', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key5");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key5=hello=world")).toBe('--from-file=' + filePath);
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "hello=world");
|
||||
})
|
||||
|
||||
test('Special characters in value', () => {
|
||||
var filePath = path.join(process.env['RUNNER_TEMP'], "key6");
|
||||
fileUtility.writeFileSync = jest.fn();
|
||||
expect(fromLiteralsToFromFile("--from-literal=key6=&^)@!&^@)")).toBe('--from-file=' + filePath);
|
||||
expect(fileUtility.writeFileSync).toBeCalledWith(filePath, "&^)@!&^@)");
|
||||
})
|
|
@ -0,0 +1,10 @@
|
|||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: true
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createFile = void 0;
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
/**
|
||||
*
|
||||
* @param fileName The fileName in case of a file needs to be created in TEMP folder else the entire filepath
|
||||
* @param data File data
|
||||
* @param inTempFolder Boolean to indicate if file needs to be created in TEMP folder
|
||||
*/
|
||||
function createFile(fileName, data, inTempFolder) {
|
||||
const filePath = inTempFolder ? path.join(process.env['RUNNER_TEMP'], fileName) : fileName;
|
||||
try {
|
||||
fs.writeFileSync(filePath, data);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
exports.createFile = createFile;
|
40
lib/run.js
40
lib/run.js
|
@ -1,19 +1,22 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.fromLiteralsToFromFile = void 0;
|
||||
const toolCache = require("@actions/tool-cache");
|
||||
const core = require("@actions/core");
|
||||
const toolrunner_1 = require("@actions/exec/lib/toolrunner");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
const io = require("@actions/io");
|
||||
const fileUtility = require("./file.utility");
|
||||
let kubectlPath = "";
|
||||
function checkAndSetKubectlPath() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
|
@ -90,10 +93,43 @@ function getDockerSecretArguments(secretName) {
|
|||
}
|
||||
function getGenericSecretArguments(secretName) {
|
||||
const secretArguments = core.getInput('arguments');
|
||||
const parsedArgument = fromLiteralsToFromFile(secretArguments);
|
||||
let args = ['create', 'secret', 'generic', secretName];
|
||||
args.push(...toolrunner_1.argStringToArray(secretArguments));
|
||||
args.push(...toolrunner_1.argStringToArray(parsedArgument));
|
||||
return args;
|
||||
}
|
||||
/**
|
||||
* Takes a valid kubectl arguments and parses --from-literal to --from-file
|
||||
* @param secretArguments
|
||||
*/
|
||||
function fromLiteralsToFromFile(secretArguments) {
|
||||
const parsedArgument = secretArguments.split("--").reduce((argumentsBuilder, argument) => {
|
||||
if (argument && !argument.startsWith("from-literal=")) {
|
||||
argumentsBuilder = argumentsBuilder.trim() + " --" + argument;
|
||||
}
|
||||
else if (argument && argument.startsWith("from-literal=")) {
|
||||
const command = argument.substring("from-literal=".length);
|
||||
/* The command starting after 'from-literal=' contanis a 'key=value' format. The secret itself might contain a '=',
|
||||
Hence the substring than a split*/
|
||||
if (command.indexOf("=") == -1)
|
||||
throw new Error('Invalid from-literal input. It should contain a key and value');
|
||||
const secretName = command.substring(0, command.indexOf("=")).trim();
|
||||
const secretValue = command.substring(command.indexOf("=") + 1).trim();
|
||||
//Secret with spaces will be enclosed in quotes -> "secret "
|
||||
if (secretValue && secretValue.indexOf("\"") == 0 && secretValue.lastIndexOf("\"") == secretValue.length - 1) {
|
||||
const secret = secretValue.substring(1, secretValue.lastIndexOf("\""));
|
||||
argumentsBuilder += " --from-file=" + fileUtility.createFile(secretName, secret, true);
|
||||
}
|
||||
else {
|
||||
const secret = secretValue.substring(0, secretValue.indexOf(" ") == -1 ? secretValue.length : secretValue.indexOf(" "));
|
||||
argumentsBuilder += " --from-file=" + fileUtility.createFile(secretName, secret, true);
|
||||
}
|
||||
}
|
||||
return argumentsBuilder;
|
||||
});
|
||||
return parsedArgument.trim();
|
||||
}
|
||||
exports.fromLiteralsToFromFile = fromLiteralsToFromFile;
|
||||
function checkClusterContext() {
|
||||
if (!process.env["KUBECONFIG"]) {
|
||||
throw new Error('Cluster context not set. Use k8s-set-context/aks-set-context action to set cluster context');
|
||||
|
|
|
@ -68,4 +68,4 @@
|
|||
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
"private": true,
|
||||
"main": "lib/run.js",
|
||||
"scripts": {
|
||||
"build": "tsc --outDir .\\lib\\ --rootDir .\\src\\"
|
||||
"build": "tsc --outDir .\\lib\\ --rootDir .\\src\\",
|
||||
"test": "jest"
|
||||
},
|
||||
"keywords": [
|
||||
"actions",
|
||||
|
@ -19,6 +20,10 @@
|
|||
"@actions/tool-cache": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.0.4"
|
||||
"@types/node": "^12.0.4",
|
||||
"jest": "^26.0.1",
|
||||
"@types/jest": "^25.2.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"typescript": "^3.9.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import fs = require("fs");
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param fileName The fileName in case of a file needs to be created in TEMP folder else the entire filepath
|
||||
* @param data File data
|
||||
* @param inTempFolder Boolean to indicate if file needs to be created in TEMP folder
|
||||
*/
|
||||
export function createFile(fileName: string, data: string, inTempFolder: boolean): string {
|
||||
const filePath = inTempFolder ? path.join(process.env['RUNNER_TEMP'], fileName) : fileName;
|
||||
try {
|
||||
fs.writeFileSync(filePath, data);
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return filePath;
|
||||
}
|
34
src/run.ts
34
src/run.ts
|
@ -6,6 +6,8 @@ import * as path from 'path';
|
|||
import * as os from 'os';
|
||||
import * as io from '@actions/io';
|
||||
|
||||
import fileUtility = require('./file.utility')
|
||||
|
||||
let kubectlPath = "";
|
||||
|
||||
async function checkAndSetKubectlPath() {
|
||||
|
@ -95,11 +97,41 @@ function getDockerSecretArguments(secretName: string): string[] {
|
|||
|
||||
function getGenericSecretArguments(secretName: string): string[] {
|
||||
const secretArguments = core.getInput('arguments');
|
||||
const parsedArgument = fromLiteralsToFromFile(secretArguments);
|
||||
let args = ['create', 'secret', 'generic', secretName];
|
||||
args.push(...argStringToArray(secretArguments));
|
||||
args.push(...argStringToArray(parsedArgument));
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a valid kubectl arguments and parses --from-literal to --from-file
|
||||
* @param secretArguments
|
||||
*/
|
||||
export function fromLiteralsToFromFile(secretArguments: string): string {
|
||||
const parsedArgument = secretArguments.split("--").reduce((argumentsBuilder, argument) => {
|
||||
if (argument && !argument.startsWith("from-literal=")) {
|
||||
argumentsBuilder = argumentsBuilder.trim() + " --" + argument;
|
||||
} else if (argument && argument.startsWith("from-literal=")) {
|
||||
const command = argument.substring("from-literal=".length);
|
||||
/* The command starting after 'from-literal=' contanis a 'key=value' format. The secret itself might contain a '=',
|
||||
Hence the substring than a split*/
|
||||
if (command.indexOf("=") == -1) throw new Error('Invalid from-literal input. It should contain a key and value');
|
||||
const secretName = command.substring(0, command.indexOf("=")).trim();
|
||||
const secretValue = command.substring(command.indexOf("=") + 1).trim();
|
||||
//Secret with spaces will be enclosed in quotes -> "secret "
|
||||
if (secretValue && secretValue.indexOf("\"") == 0 && secretValue.lastIndexOf("\"") == secretValue.length - 1) {
|
||||
const secret = secretValue.substring(1, secretValue.lastIndexOf("\""));
|
||||
argumentsBuilder += " --from-file=" + fileUtility.createFile(secretName, secret, true);
|
||||
} else {
|
||||
const secret = secretValue.substring(0, secretValue.indexOf(" ") == -1 ? secretValue.length : secretValue.indexOf(" "));
|
||||
argumentsBuilder += " --from-file=" + fileUtility.createFile(secretName, secret, true);
|
||||
}
|
||||
}
|
||||
return argumentsBuilder;
|
||||
});
|
||||
return parsedArgument.trim();
|
||||
}
|
||||
|
||||
function checkClusterContext() {
|
||||
if (!process.env["KUBECONFIG"]) {
|
||||
throw new Error('Cluster context not set. Use k8s-set-context/aks-set-context action to set cluster context');
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"module": "commonjs"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
"node_modules",
|
||||
"__tests__"
|
||||
]
|
||||
}
|
Загрузка…
Ссылка в новой задаче