Refactor gh secret testscript
This is a bit of a refactor based on the work done in `gh workflow` as a better approach to verify secrets created are what we expect. Changes made: 1. Removed `env2lower` as it wasn't being used in testscripts 2. Added `replace` custom command to deal with testing organization workflow secrets 3. Refactored secret testscripts to create and run workflow that tests the value of the secret provided 4. Minor reordering of test `acceptance` test functions as appending to the end is confusing and adds conflicts 5. Removed stdout TTY assertions
This commit is contained in:
parent
1571a113c2
commit
f4f161c096
5 changed files with 272 additions and 75 deletions
|
|
@ -72,13 +72,6 @@ The following custom commands are defined within [`acceptance_test.go`](./accept
|
|||
defer gh repo delete --yes $ORG/$SCRIPT_NAME-$RANDOM_STRING
|
||||
```
|
||||
|
||||
- `env2lower`: set environment variable to the lowercase version of another environment variable
|
||||
|
||||
```txtar
|
||||
# Prepare repository name, which is only lowercase
|
||||
env2lower REPO_NAME=$RANDOM_STRING
|
||||
```
|
||||
|
||||
- `env2upper`: set environment variable to the uppercase version of another environment variable
|
||||
|
||||
```txtar
|
||||
|
|
@ -86,6 +79,22 @@ The following custom commands are defined within [`acceptance_test.go`](./accept
|
|||
env2upper ORG_SECRET_NAME=$RANDOM_STRING
|
||||
```
|
||||
|
||||
- `replace`: replace placeholders in file with interpolated content provided
|
||||
|
||||
```txtar
|
||||
env2upper SECRET_NAME=$SCRIPT_NAME_$RANDOM_STRING
|
||||
|
||||
# Modify workflow file to use generated organization secret name
|
||||
mv ../workflow.yml .github/workflows/workflow.yml
|
||||
replace .github/workflows/workflow.yml SECRET_NAME=$SECRET_NAME
|
||||
|
||||
-- workflow.yml --
|
||||
on:
|
||||
workflow_dispatch:
|
||||
env:
|
||||
ORG_SECRET: ${{ secrets.$SECRET_NAME }}
|
||||
```
|
||||
|
||||
- `stdout2env`: set environment variable containing standard output from previous command
|
||||
|
||||
```txtar
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ func TestMain(m *testing.M) {
|
|||
}))
|
||||
}
|
||||
|
||||
func TestPullRequests(t *testing.T) {
|
||||
func TestAPI(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "pr"))
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "api"))
|
||||
}
|
||||
|
||||
func TestIssues(t *testing.T) {
|
||||
|
|
@ -45,6 +45,24 @@ func TestIssues(t *testing.T) {
|
|||
testscript.Run(t, testScriptParamsFor(tsEnv, "pr"))
|
||||
}
|
||||
|
||||
func TestPullRequests(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "pr"))
|
||||
}
|
||||
|
||||
func TestReleases(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "release"))
|
||||
}
|
||||
|
||||
func TestSecrets(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
|
|
@ -63,25 +81,6 @@ func TestWorkflows(t *testing.T) {
|
|||
testscript.Run(t, testScriptParamsFor(tsEnv, "workflow"))
|
||||
}
|
||||
|
||||
func TestAPI(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "api"))
|
||||
}
|
||||
|
||||
func TestReleases(t *testing.T) {
|
||||
var tsEnv testScriptEnv
|
||||
if err := tsEnv.fromEnv(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testscript.Run(t, testScriptParamsFor(tsEnv, "release"))
|
||||
>>>>>>> trunk
|
||||
}
|
||||
|
||||
func testScriptParamsFor(tsEnv testScriptEnv, command string) testscript.Params {
|
||||
var files []string
|
||||
if tsEnv.script != "" {
|
||||
|
|
@ -156,23 +155,6 @@ func sharedCmds(tsEnv testScriptEnv) map[string]func(ts *testscript.TestScript,
|
|||
}
|
||||
})
|
||||
},
|
||||
"env2lower": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
if neg {
|
||||
ts.Fatalf("unsupported: ! env2lower")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
ts.Fatalf("usage: env2lower name=value ...")
|
||||
}
|
||||
for _, env := range args {
|
||||
i := strings.Index(env, "=")
|
||||
|
||||
if i < 0 {
|
||||
ts.Fatalf("env2lower: argument does not match name=value")
|
||||
}
|
||||
|
||||
ts.Setenv(env[:i], strings.ToLower(env[i+1:]))
|
||||
}
|
||||
},
|
||||
"env2upper": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
if neg {
|
||||
ts.Fatalf("unsupported: ! env2upper")
|
||||
|
|
@ -190,6 +172,41 @@ func sharedCmds(tsEnv testScriptEnv) map[string]func(ts *testscript.TestScript,
|
|||
ts.Setenv(env[:i], strings.ToUpper(env[i+1:]))
|
||||
}
|
||||
},
|
||||
"replace": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
if neg {
|
||||
ts.Fatalf("unsupported: ! replace")
|
||||
}
|
||||
if len(args) < 2 {
|
||||
ts.Fatalf("usage: replace file env...")
|
||||
}
|
||||
|
||||
src := ts.MkAbs(args[0])
|
||||
ts.Logf("replace src: %s", src)
|
||||
info, err := os.Stat(src)
|
||||
ts.Check(err)
|
||||
mode := info.Mode() & 0o777
|
||||
data, err := os.ReadFile(src)
|
||||
ts.Check(err)
|
||||
|
||||
for _, arg := range args[1:] {
|
||||
i := strings.Index(arg, "=")
|
||||
if i < 0 {
|
||||
ts.Fatalf("replace: %s argument does not match name=value", arg)
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("$%s", arg[:i])
|
||||
value := arg[i+1:]
|
||||
ts.Logf("replace %s: %s", name, value)
|
||||
|
||||
// `replace` was originally built similar to `cmpenv`, expanding environment variables within a file.
|
||||
// However files with content that looks like environments variable such as GitHub Actions workflows
|
||||
// were being modified unexpectedly. Thus `replace` has been designed to using string replacement
|
||||
// looking for `$KEY` specifically.
|
||||
data = []byte(strings.ReplaceAll(string(data), name, value))
|
||||
}
|
||||
|
||||
ts.Check(os.WriteFile(src, data, mode))
|
||||
},
|
||||
"stdout2env": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
if neg {
|
||||
ts.Fatalf("unsupported: ! stdout2env")
|
||||
|
|
|
|||
85
acceptance/testdata/secret/secret-org.txtar
vendored
85
acceptance/testdata/secret/secret-org.txtar
vendored
|
|
@ -1,16 +1,85 @@
|
|||
# Prepare organization secret, GitHub Actions uppercases secret names
|
||||
env2upper ORG_SECRET_NAME=$RANDOM_STRING
|
||||
# Setup environment variables used for testscript
|
||||
env REPO=$SCRIPT_NAME-$RANDOM_STRING
|
||||
env2upper SECRET_NAME=$SCRIPT_NAME_$RANDOM_STRING
|
||||
|
||||
# Use gh as a credential helper
|
||||
exec gh auth setup-git
|
||||
|
||||
# Create a repository with a file so it has a default branch
|
||||
exec gh repo create $ORG/$REPO --add-readme --private
|
||||
|
||||
# Defer repo cleanup
|
||||
defer gh repo delete --yes $ORG/$REPO
|
||||
|
||||
# Clone the repo
|
||||
exec gh repo clone $ORG/$REPO
|
||||
cd $REPO
|
||||
|
||||
# Confirm organization secret does not exist, will fail admin:org scope missing
|
||||
! exec gh api /orgs/$ORG/actions/secrets/$ORG_SECRET_NAME
|
||||
stdout '"status":"404"'
|
||||
exec gh secret list --org $ORG
|
||||
! stdout $SECRET_NAME
|
||||
|
||||
# Create an organization secret
|
||||
exec gh secret set $ORG_SECRET_NAME --org $ORG --body 'does not matter as cannot read it once set'
|
||||
exec gh secret set $SECRET_NAME --org $ORG --body 'just an organization secret' --repos $REPO
|
||||
|
||||
# Defer organization secret cleanup
|
||||
defer gh secret delete $ORG_SECRET_NAME --org $ORG
|
||||
defer gh secret delete $SECRET_NAME --org $ORG
|
||||
|
||||
# Confirm organization secret exists
|
||||
# Verify new organization secret exists
|
||||
exec gh secret list --org $ORG
|
||||
stdout $ORG_SECRET_NAME
|
||||
stdout $SECRET_NAME
|
||||
|
||||
# Commit workflow file creating dispatchable workflow able to verify secret matches
|
||||
mkdir .github/workflows
|
||||
mv ../workflow.yml .github/workflows/workflow.yml
|
||||
replace .github/workflows/workflow.yml SECRET_NAME=$SECRET_NAME
|
||||
exec git add .github/workflows/workflow.yml
|
||||
exec git commit -m 'Create workflow file'
|
||||
exec git push -u origin main
|
||||
|
||||
# Sleep because it takes a second for the workflow to register
|
||||
sleep 1
|
||||
|
||||
# Check the workflow is indeed created
|
||||
exec gh workflow list
|
||||
stdout 'Test Workflow Name'
|
||||
|
||||
# Run the workflow
|
||||
exec gh workflow run 'Test Workflow Name'
|
||||
|
||||
# It takes some time for a workflow run to register
|
||||
sleep 10
|
||||
|
||||
# Get the run ID we want to watch & delete
|
||||
exec gh run list --json databaseId --jq '.[0].databaseId'
|
||||
stdout2env RUN_ID
|
||||
|
||||
# Wait for workflow to complete
|
||||
exec gh run watch $RUN_ID --exit-status
|
||||
|
||||
# Verify secret matched what was set earlier
|
||||
exec gh run view $RUN_ID --log
|
||||
stdout 'GitHub Actions secret value matches$'
|
||||
|
||||
-- workflow.yml --
|
||||
# This workflow is intended to assert the value of the GitHub Actions secret was set appropriately
|
||||
name: Test Workflow Name
|
||||
on:
|
||||
# Allow workflow to be dispatched by gh workflow run
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# This workflow contains a single job called "assert" that should only pass if the GitHub Actions secret value matches
|
||||
assert:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Assert secret value matches
|
||||
env:
|
||||
ORG_SECRET: ${{ secrets.$SECRET_NAME }}
|
||||
run: |
|
||||
if [[ "$ORG_SECRET" == "just an organization secret" ]]; then
|
||||
echo "GitHub Actions secret value matches"
|
||||
else
|
||||
echo "GitHub Actions secret value does not match"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
75
acceptance/testdata/secret/secret-repo-env.txtar
vendored
75
acceptance/testdata/secret/secret-repo-env.txtar
vendored
|
|
@ -1,8 +1,10 @@
|
|||
# Force GitHub CLI to treat testscript as TTY
|
||||
env GH_FORCE_TTY=80
|
||||
# Setup environment variables used for testscript
|
||||
env REPO=$SCRIPT_NAME-$RANDOM_STRING
|
||||
|
||||
# Create a repository where the secret will be registered
|
||||
# Use gh as a credential helper
|
||||
exec gh auth setup-git
|
||||
|
||||
# Create a repository with a file so it has a default branch
|
||||
exec gh repo create $ORG/$REPO --add-readme --private
|
||||
|
||||
# Defer repo cleanup
|
||||
|
|
@ -13,17 +15,66 @@ exec gh repo clone $ORG/$REPO
|
|||
cd $REPO
|
||||
|
||||
# Create a repository environment, will fail if organization does not have environment support
|
||||
exec gh api /repos/$ORG/$REPO/environments/testscripts -X PUT --jq '.name'
|
||||
stdout 'testscripts'
|
||||
|
||||
# Verify no repository environment secrets exist
|
||||
exec gh secret list --env testscripts
|
||||
stderr 'no secrets found'
|
||||
exec gh api /repos/$ORG/$REPO/environments/testscripts -X PUT
|
||||
|
||||
# Create a repository environment secret
|
||||
exec gh secret set TESTSCRIPTS_ENV --env testscripts --body 'does not matter as cannot read it once set'
|
||||
stdout 'Set Actions secret TESTSCRIPTS_ENV for'
|
||||
exec gh secret set TESTSCRIPTS_ENV --env testscripts --body 'just a repository environment secret'
|
||||
|
||||
# Verify new repository secret exists
|
||||
exec gh secret list --env testscripts
|
||||
stdout 'TESTSCRIPTS_ENV\s+less than a minute ago'
|
||||
stdout 'TESTSCRIPTS_ENV'
|
||||
|
||||
# Commit workflow file creating dispatchable workflow able to verify secret matches
|
||||
mkdir .github/workflows
|
||||
mv ../workflow.yml .github/workflows/workflow.yml
|
||||
exec git add .github/workflows/workflow.yml
|
||||
exec git commit -m 'Create workflow file'
|
||||
exec git push -u origin main
|
||||
|
||||
# Sleep because it takes a second for the workflow to register
|
||||
sleep 1
|
||||
|
||||
# Check the workflow is indeed created
|
||||
exec gh workflow list
|
||||
stdout 'Test Workflow Name'
|
||||
|
||||
# Run the workflow
|
||||
exec gh workflow run 'Test Workflow Name'
|
||||
|
||||
# It takes some time for a workflow run to register
|
||||
sleep 10
|
||||
|
||||
# Get the run ID we want to watch & delete
|
||||
exec gh run list --json databaseId --jq '.[0].databaseId'
|
||||
stdout2env RUN_ID
|
||||
|
||||
# Wait for workflow to complete
|
||||
exec gh run watch $RUN_ID --exit-status
|
||||
|
||||
# Verify secret matched what was set earlier
|
||||
exec gh run view $RUN_ID --log
|
||||
stdout 'GitHub Actions secret value matches$'
|
||||
|
||||
-- workflow.yml --
|
||||
# This workflow is intended to assert the value of the GitHub Actions secret was set appropriately
|
||||
name: Test Workflow Name
|
||||
on:
|
||||
# Allow workflow to be dispatched by gh workflow run
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# This workflow contains a single job called "assert" that should only pass if the GitHub Actions secret value matches
|
||||
assert:
|
||||
runs-on: ubuntu-latest
|
||||
environment: testscripts
|
||||
steps:
|
||||
- name: Assert secret value matches
|
||||
env:
|
||||
TESTSCRIPTS_ENV: ${{ secrets.TESTSCRIPTS_ENV }}
|
||||
run: |
|
||||
if [[ "$TESTSCRIPTS_ENV" == "just a repository environment secret" ]]; then
|
||||
echo "GitHub Actions secret value matches"
|
||||
else
|
||||
echo "GitHub Actions secret value does not match"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
71
acceptance/testdata/secret/secret-repo.txtar
vendored
71
acceptance/testdata/secret/secret-repo.txtar
vendored
|
|
@ -1,8 +1,10 @@
|
|||
# Force GitHub CLI to treat testscript as TTY
|
||||
env GH_FORCE_TTY=80
|
||||
# Setup environment variables used for testscript
|
||||
env REPO=$SCRIPT_NAME-$RANDOM_STRING
|
||||
|
||||
# Create a repository where the secret will be registered
|
||||
# Use gh as a credential helper
|
||||
exec gh auth setup-git
|
||||
|
||||
# Create a repository with a file so it has a default branch
|
||||
exec gh repo create $ORG/$REPO --add-readme --private
|
||||
|
||||
# Defer repo cleanup
|
||||
|
|
@ -12,14 +14,63 @@ defer gh repo delete --yes $ORG/$REPO
|
|||
exec gh repo clone $ORG/$REPO
|
||||
cd $REPO
|
||||
|
||||
# Verify no repository secrets exist
|
||||
exec gh secret list
|
||||
stderr 'no secrets found'
|
||||
|
||||
# Create a repository secret
|
||||
exec gh secret set TESTSCRIPTS --body 'does not matter as cannot read it once set'
|
||||
stdout 'Set Actions secret TESTSCRIPTS for'
|
||||
exec gh secret set TESTSCRIPTS --body 'just a repository secret'
|
||||
|
||||
# Verify new repository secret exists
|
||||
exec gh secret list
|
||||
stdout 'TESTSCRIPTS\s+less than a minute ago'
|
||||
stdout 'TESTSCRIPTS'
|
||||
|
||||
# Commit workflow file creating dispatchable workflow able to verify secret matches
|
||||
mkdir .github/workflows
|
||||
mv ../workflow.yml .github/workflows/workflow.yml
|
||||
exec git add .github/workflows/workflow.yml
|
||||
exec git commit -m 'Create workflow file'
|
||||
exec git push -u origin main
|
||||
|
||||
# Sleep because it takes a second for the workflow to register
|
||||
sleep 1
|
||||
|
||||
# Check the workflow is indeed created
|
||||
exec gh workflow list
|
||||
stdout 'Test Workflow Name'
|
||||
|
||||
# Run the workflow
|
||||
exec gh workflow run 'Test Workflow Name'
|
||||
|
||||
# It takes some time for a workflow run to register
|
||||
sleep 10
|
||||
|
||||
# Get the run ID we want to watch & delete
|
||||
exec gh run list --json databaseId --jq '.[0].databaseId'
|
||||
stdout2env RUN_ID
|
||||
|
||||
# Wait for workflow to complete
|
||||
exec gh run watch $RUN_ID --exit-status
|
||||
|
||||
# Verify secret matched what was set earlier
|
||||
exec gh run view $RUN_ID --log
|
||||
stdout 'GitHub Actions secret value matches$'
|
||||
|
||||
-- workflow.yml --
|
||||
# This workflow is intended to assert the value of the GitHub Actions secret was set appropriately
|
||||
name: Test Workflow Name
|
||||
on:
|
||||
# Allow workflow to be dispatched by gh workflow run
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# This workflow contains a single job called "assert" that should only pass if the GitHub Actions secret value matches
|
||||
assert:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Assert secret value matches
|
||||
env:
|
||||
TESTSCRIPTS: ${{ secrets.TESTSCRIPTS }}
|
||||
run: |
|
||||
if [[ "$TESTSCRIPTS" == "just a repository secret" ]]; then
|
||||
echo "GitHub Actions secret value matches"
|
||||
else
|
||||
echo "GitHub Actions secret value does not match"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue