Skip to content

made auth optional, added support for data files and vars #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 38 additions & 45 deletions .github/workflows/stackql-assert.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,65 +17,58 @@ jobs:
- name: Checkout
uses: actions/checkout@v3


- name: Prep Google Creds (Windows)
if: ${{ matrix.os == 'windows-latest'}}
run: | ## use the secret to create json file
$GoogleCreds = [System.Environment]::GetEnvironmentVariable("GOOGLE_CREDS_ENV")
$GoogleCredsDecoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($GoogleCreds))
Write-Output $GoogleCredsDecoded | Set-Content sa-key.json
shell: pwsh
env:
GOOGLE_CREDS_ENV: ${{ secrets.GOOGLE_CREDS }}

- name: Prep Google Creds (bash)
if: ${{ matrix.os != 'windows-latest' }}
shell: bash
run: | ## use the base64 encoded secret to create json file
sudo echo ${{ secrets.GOOGLE_CREDS }} | base64 -d > sa-key.json

- name: Use test query string and expected results string with auth object
#
# Example `test_query` with `expected_rows`
#
- name: Use test query string and expected rows
uses: ./
with:
auth_obj_path: './.github/workflows/workflow_scripts/auth.json'
test_query: |
REGISTRY PULL google v23.01.00116;
REGISTRY PULL google;
SELECT name
FROM google.compute.instances
WHERE project = 'stackql-demo' AND zone = 'australia-southeast1-a' AND name = 'stackql-demo-001';
expected_results_str: ' [{"name":"stackql-demo-001"}]'
expected_rows: 1
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}

- name: Use test query file and expected result string with auth object
#
# Example `test_query_file_path` with `expected_results_str`
#
- name: Use test query file and expected result string
uses: ./
with:
auth_obj_path: './.github/workflows/workflow_scripts/auth.json'
test_query_file_path: './.github/workflows/workflow_scripts/google-example.iql'
expected_results_str: ' [{"name":"stackql-demo-001"}]'

- name: Use test query string and expected results string, with auth string
uses: ./
with:
auth_str: '{ "google": { "type": "service_account", "credentialsfilepath": "sa-key.json" }}'
test_query: |
REGISTRY PULL google v23.01.00116;
SELECT name
FROM google.compute.instances
WHERE project = 'stackql-demo' AND zone = 'australia-southeast1-a' AND name = 'stackql-demo-001';
expected_results_str: '[{"name":"stackql-demo-001"}]'
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}

- name: Use test query string and expected results file, with auth object
#
# Example `test_query_file_path` with `expected_results_file_path` supplying `vars` using an inline `jsonnet` config block
#
- name: Use test query file and expected results file path using inline jsonnet config block and external vars
uses: ./
with:
auth_obj_path: './.github/workflows/workflow_scripts/auth.json'
test_query_file_path: './.github/workflows/workflow_scripts/google-example.iql'
expected_results_str: '[{"name":"stackql-demo-001"}]'
test_query_file_path: './.github/workflows/workflow_scripts/google-example-inline-jsonnet.iql'
expected_results_file_path: './.github/workflows/workflow_scripts/google-example-inline-jsonnet-results.json'
vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}

- name: Use test query string and expected rows, with auth object
#
# Example `test_query_file_path` with `expected_rows` supplying `vars` using `jsonnet` config provided using `data_file_path`
#
- name: Use test query string and expected results file, with auth object
uses: ./
with:
auth_str: '{ "google": { "type": "service_account", "credentialsfilepath": "sa-key.json" }}'
test_query_file_path: './.github/workflows/workflow_scripts/google-example.iql'
expected_rows: 1



test_query_file_path: './.github/workflows/workflow_scripts/github-example.iql'
data_file_path: './.github/workflows/workflow_scripts/github-example-data.jsonnet'
vars: TEST_ORG=${{ env.TEST_ORG }},TEST_REPO=${{ env.TEST_REPO }}
expected_rows: 1
env:
STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
TEST_ORG: ${{ vars.TEST_ORG }}
TEST_REPO: ${{ vars.TEST_REPO }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
local org = std.extVar("TEST_ORG");
local repo = std.extVar("TEST_REPO");
{
org: org,
repo: repo,
}
7 changes: 2 additions & 5 deletions .github/workflows/workflow_scripts/github-example.iql
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
REGISTRY PULL github v23.01.00104;
SHOW PROVIDERS;
select total_private_repos
from github.orgs.orgs
where org = 'stackql';
REGISTRY PULL github;
SELECT name FROM github.repos.repos WHERE org = '{{ .org }}' AND name = '{{ .repo }}';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<<<jsonnet
local project = std.extVar("GOOGLE_PROJECT");
local zone = std.extVar("GOOGLE_ZONE");
{
project: project,
zone: zone,
}
>>>
SELECT name
FROM google.compute.instances
WHERE project = '{{ .project }}' and zone = '{{ .zone }}' and name = 'stackql-demo-001';
1 change: 0 additions & 1 deletion .github/workflows/workflow_scripts/google-example.iql
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
REGISTRY PULL google v23.01.00116;
SELECT name
FROM google.compute.instances
WHERE project = 'stackql-demo' AND zone = 'australia-southeast1-a' AND name = 'stackql-demo-001';
7 changes: 0 additions & 7 deletions .stackql/readline/readline.tmp

This file was deleted.

113 changes: 83 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,97 @@
# stackql-assert

The `stackql/stackql-assert` action is an composite action that runs stackql query and check if result matches expected result

The `stackql/stackql-assert` action is an composite action that runs a `stackql` query and checks if the result matches an expected result

# Usage

## AUTH
> **Note**
> stackql-assert action uses same auth setup as [stackql-exec](https://github.com/stackql/stackql-exec/blob/main/README.md).
> [Learn more](https://stackql.io/docs/getting-started/authenticating) about authentication setup when running stackql
## Provider Authentication
Authentication to StackQL providers is done via environment variables source from GitHub Actions Secrets. To learn more about authentication, see the setup instructions for your provider or providers at the [StackQL Provider Registry Docs](https://stackql.io/registry).

### Example auth string
```
{ "google": { "type": "service_account", "credentialsfilepath": "sa-key.json" },
"github": { "type": "basic", "credentialsenvvar": "STACKQL_GITHUB_CREDS" }}
```
It can be passed with `auth_str` as a string, or stored in a file and pass filename to `auth-obj-path`
- For "basic" auth, you need to set a environment variable with same name as the value of `credentialsenvvar` in the auth string for the Github Action step. You can use [Github Secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) to store the value of the environment variable, and use env to pass it to the action. For example:
```
env:
STACKQL_GITHUB_CREDS: ${{ secrets.STACKQL_GITHUB_CREDS }}
```
- For "service_account" auth, you need to store the credentials into a file; You can follow the example of `Prep Google Creds (bash)` step in the [example workflow](./.github/workflows/stackql-assert.yml)
## Inputs
- `test_query` - stackql query to execute **(need to supply either `test_query` or `test_query_file_path`)**
- `test_query_file_path` - stackql query file to execute **(need to supply either `test_query` or `test_query_file_path`)**
- `data_file_path` - (optional) path to data file to pass to the stackql query preprocessor (`json` or `jsonnet`)
- `vars` - (optional) comma delimited list of variables to pass to the stackql query preprocessor (supported with `jsonnet` config blocks or `jsonnet` data files only), accepts `var1=val1,var2=val2`, can be used to source environment variables into stackql queries
- `expected_rows` - (optional) Expected number of rows in the result.
- `expected_results_str` - (optional) Expected result (`json`) from executing test query, support object string (overrides `expected_results_file_path`)
- `expected_results_file_path` - (optional) Results file (`json`) that stores expected result, json is support
- `auth_obj_path` - (optional) the path of json file that stores stackql AUTH string **(only required when using non-standard environment variable names)**
- `auth_str` - (optional) stackql AUTH string **(only required when using non-standard environment variable names)**

**__NOTE:__ one of `expected_rows`, `expected_results_str` or `expected_results_file_path` is required**

## Test Query
- Use `test_query` or `test_query_path` to pass the test query to the action. The test query should be a valid StackQL query. The action will run the query and check if the result is empty or not. If the result is empty, the action will fail the step.
- Either `test_query` or `test_query_path` is required. If both are provided, `test_query` will be used.
- Use `test_query` or `test_query_file_path` to pass the test query to the action. The test query should be a valid StackQL query. The action will run the query and check if the result is empty or not. If the result is empty, the action will fail the step.
- Either `test_query` or `test_query_file_path` are required. If both are provided, `test_query` will be used.
- query example can be found in [example workflow](./.github/workflows/stackql-assert.yml) and [example .iql file](./.github/workflows/workflow_scripts)

## Expected Result
- Use `expected_results_str` or `expected_results_file_path` to pass the expected result to the action. The expected result should be a valid JSON object. The action will compare the result with the expected result. If the result is not the same as the expected result, the action will fail the step.
- Either `expected_results_str` or `expected_results_file_path` is required. If both are provided, `expected_results_str` will be used.
- Use `expected_results_str` or `expected_results_file_path` or `expected_rows` to pass the expected result to the action. The expected result (`expected_results_str` or `expected_results_file_path`) should be a valid `json` object. The action will compare the result with the expected result. If the result is not the same as the expected result, the action will fail the step.
- Either `expected_results_str` or `expected_results_file_path` or `expected_rows` are required. If `expected_results_str` and `expected_results_file_path` are provided, `expected_results_str` will be used.
- Expected result example can be found in [example workflow](./.github/workflows/stackql-assert.yml) and [example .json file](./.github/workflows/workflow_scripts)

## Examples
The following excerpts from a GitHub Actions workflow demonstrate how to use the `stackql/stackql-assert` action.

## Example `test_query` with `expected_rows`

```yaml
- name: Use test query string and expected rows
uses: ./
with:
test_query: |
REGISTRY PULL google;
SELECT name
FROM google.compute.instances
WHERE project = 'stackql-demo' AND zone = 'australia-southeast1-a' AND name = 'stackql-demo-001';
expected_rows: 1
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
```

## Example `test_query_file_path` with `expected_results_str`

```yaml
- name: Use test query file and expected result string
uses: ./
with:
test_query_file_path: './.github/workflows/workflow_scripts/google-example.iql'
expected_results_str: '[{"name":"stackql-demo-001"}]'
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
```

## Example `test_query_file_path` with `expected_results_file_path` supplying `vars` using an inline `jsonnet` config block

```yaml
- name: Use test query file and expected results file path using inline jsonnet config block and external vars
uses: ./
with:
test_query_file_path: './.github/workflows/workflow_scripts/google-example-inline-jsonnet.iql'
expected_results_file_path: './.github/workflows/workflow_scripts/google-example-inline-jsonnet-results.json'
vars: GOOGLE_PROJECT=${{ env.GOOGLE_PROJECT }},GOOGLE_ZONE=${{ env.GOOGLE_ZONE }}
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
GOOGLE_PROJECT: ${{ vars.GOOGLE_PROJECT }}
GOOGLE_ZONE: ${{ vars.GOOGLE_ZONE }}
```

## Example `test_query_file_path` with `expected_rows` supplying `vars` using `jsonnet` config provided using `data_file_path`

```yaml
- name: Use test query string and expected results file, with auth object
uses: ./
with:
test_query_file_path: './.github/workflows/workflow_scripts/google-example.iql'
data_file_path: './.github/workflows/workflow_scripts/google-example-data.jsonnet'
vars: TEST_ORG=${{ env.TEST_ORG }},TEST_REPO=${{ env.TEST_REPO }}
expected_rows: 1
env:
STACKQL_GITHUB_USERNAME: ${{ secrets.STACKQL_GITHUB_USERNAME }}
STACKQL_GITHUB_PASSWORD: ${{ secrets.STACKQL_GITHUB_PASSWORD }}
TEST_ORG: ${{ vars.TEST_ORG }}
TEST_REPO: ${{ vars.TEST_REPO }}
```



## Input
- `auth_obj_path` - Path to the auth object file.
- `auth_str` - Auth string.
- `test_query` - Test query to run (overrides test_query_path).
- `test_query_file_path` - Path to the test query file.
- `expected_rows` - Expected number of rows in the result.
- `expected_results_str` - expected result from executing test query, support object string (overrides expected_results_file_path)
- `expected_results_file_path` - file that stores expected result, json is support
30 changes: 19 additions & 11 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@ name: 'StackQL Studios - StackQL Assert'
description: 'run StackQL query to test and audit your infrastructure.'
author: 'Yuncheng Yang, StackQL Studios'
inputs:
auth_obj_path:
description: file path to json object of stackql auth
required: false
auth_str:
description: json string of stackql auth
required: false
test_query:
description: stackql query to be executed
description: stackql query to execute (need to supply either test_query or test_query_file_path)
required: false
test_query_file_path:
description: stackql query file to be executed
description: stackql query file to execute (need to supply either test_query or test_query_file_path)
required: false
data_file_path:
description: path to data file to pass to the stackql query preprocessor (json or jsonnet file)
required: false
vars:
description: comma delimited list of variables to pass to the stackql query preprocessor (supported with jsonnet config blocks or jsonnet data files only), accepts 'var1=val1,var2=val2', can be used to source environment variables into stackql queries
required: false
expected_rows:
description: expected number of rows from executing test query
required: false
expected_results_str:
description: expected result from executing test query, support json string, overrides expected_results_file_path
description: expected result (as a json string) from executing test query, overrides expected_results_file_path
required: false
expected_results_file_path:
description: file that stores expected result, json is support
description: json file with the expected result
required: false
auth_obj_path:
description: the path of json file that stores stackql AUTH string (only required when using non-standard environment variable names)
required: false
auth_str:
description: stackql AUTH string (only required when using non-standard environment variable names)
required: false

runs:
Expand All @@ -39,7 +45,7 @@ runs:


- name: Setup StackQL
uses: stackql/setup-stackql@v1.1.0
uses: stackql/setup-stackql@v1.2.0
if: ${{steps.check-stackql.outputs.stackql_installed == 'false'}}
with:
use_wrapper: true
Expand Down Expand Up @@ -68,6 +74,8 @@ runs:
env:
QUERY_FILE_PATH: ${{ inputs.test_query_file_path }}
QUERY: ${{inputs.test_query}}
DATA_FILE_PATH: ${{inputs.data_file_path}}
VARS: ${{inputs.vars}}
OUTPUT: 'json'

- name: execute stackql command
Expand Down
32 changes: 21 additions & 11 deletions lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,32 @@ const checkResult = (expectedResult, expectedRows, actualResult) => {
// if both passed, check both
if (expectedRows) {
equality = actualResult.length === expectedRows;
message = `============ StackQL Assert Failed ============ \n
Expected Number of Rows: ${expectedRows} \n
Actual Number of Rows: ${actualResult.length}
Execution Result: ${JSON.stringify(actualResult)}
`;
if(equality) {
message = `============ StackQL Assert Successful (row count) ============ \n
Expected Number of Rows: ${expectedRows} \n
Actual Number of Rows: ${actualResult.length} \n
`;
} else {
message = `============ StackQL Assert Failed (row count) ============ \n
Expected Number of Rows: ${expectedRows} \n
Actual Number of Rows: ${actualResult.length} \n
Execution Result: ${JSON.stringify(actualResult)} \n
`;
}
}

if (expectedResult) {
equality = JSON.stringify(expectedResult) === JSON.stringify(actualResult);
message = `============ StackQL Assert Failed ============ \n
Expected: ${JSON.stringify(expectedResult)}\n
Actual: ${JSON.stringify(actualResult)}
`;
if(equality) {
message = `============ StackQL Assert Successful (expected results) ============`;
} else {
message = `============ StackQL Assert Failed (expected results) ============ \n
Expected: ${JSON.stringify(expectedResult)}\n
Actual: ${JSON.stringify(actualResult)}
`;
}
}


return { equality, message };
};

Expand Down Expand Up @@ -106,7 +116,7 @@ const assertResult = (coreObj) =>{

const {equality, message} = checkResult(expectedResult, expectedRows, actualResult);
if (equality) {
core.info("============ StackQL Assert Succeed ============ ");
core.info(message);
} else {
core.setFailed(message);
}
Expand Down
Loading