Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
62 changes: 49 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ vet https://example.com/setup.sh --user myuser --version latest

# Non-interactive mode for trusted scripts in automated environments (e.g., CI/CD)
vet --force https://my-trusted-internal-script.sh

# Example setting a VET_AUTH_TOKEN from standared input for private repository access
echo <YOUR_ACCESS_TOKEN> | vet --token-stdin https://example.com/private.sh
```

#### Options
Expand All @@ -141,28 +144,61 @@ Use ~/.netrc credentials for authentication.

Set authentication token from standard input.

#### Authentication
\--auth-header \<TPL>

`vet` can:
Use a custom header template for token authentication. The template must contain {} as a placeholder for the token. This is the most flexible way to authenticate. Example: `--auth-header "PRIVATE-TOKEN: {}"`

- Read from a `~/.netrc` file.
### Authentication

`vet` supports two main authentication methods: token-based (recommended for its flexibility) and `.netrc`. Token-based authentication will always be used if a token is provided.

#### Token-Based Authentication
To support various services like GitHub, GitLab, and private artifact repositories, `vet` allows you to define a custom authentication header. This is a two-part system: you provide the header template and the token itself.

#### 1. Providing the Header Template
You can specify the format of the authentication header using:
* The `--auth-header "TEMPLATE"` flag (takes highest precedence).
* The `VET_AUTH_HEADER` environment variable.

The template must contain `{}` which will be replaced with your token. If you don't provide a template, `vet` will use a default of `"Authorization: Bearer {}"`.

#### 2. Providing the Token

You can provide the secret token using:
* The `--token-stdin` flag, by piping the token to `vet`.
* The `VET_AUTH_TOKEN` environment variable.
---
#### Examples

#### Example 1: Accessing a private GitLab repository
GitLab uses the `PRIVATE-TOKEN` header. We can provide our token from an environment variable and specify the header format with the flag.
```bash
# Your GitLab Personal Access Token
export VET_AUTH_TOKEN="glpat-123xyz..."

# Use the --auth-header flag to specify GitLab's format
vet --auth-header "PRIVATE-TOKEN: {}" https://gitlab.com/api/v4/projects/.../raw
```
#### Example 2: Accessing a private GitHub repository using the GitHub CLI
GitHub requires an `Authorization: token ...` header for classic PATs. We can securely pipe the token directly from the gh CLI.
```bash
# Pipe the token from `gh auth token` and provide the correct header template
gh auth token | vet --token-stdin --auth-header "Authorization: token {}" https://raw.githubusercontent.com/owner/private-repo/main/script.sh
```
---
#### `.netrc` File
As a fallback, `vet` can read credentials from a `~/.netrc` file if the `-n`, `--netrc` flag is used. This method will be ignored if `VET_AUTH_TOKEN` is set or `--token-stdin` is used.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my research, wget will read a .netrc file by default if it exists. Curl required the -n flag to be set. It may be .netrc would take priority over other auth methods if wget were managing the connection.


- Read from a `~/.netrc` file.
```bash
# Example ~/.netrc file to authenticate with GitHub private repositories
machine raw.githubusercontent.com
login api
password <YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>
```

- Detect and read a `$VET_TOKEN` from an environment variable into an `Authorization` token.
```bash
# Example setting a VET_TOKEN from an environment variable for private GitHub repository access
export VET_TOKEN=<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>
```

- Read an `Authorization` token from standard input.
Then run with the flag:
```bash
# Example setting a VET_TOKEN from standared input for private GitHub repository access
echo <YOUR_GITHUB_PERSONAL_ACCESS_TOKEN> | ./vet --token-stdin https://example.com/private.sh
vet -n https://raw.githubusercontent.com/owner/private-repo/main/script.sh
```

## Project Philosophy & Technical Decisions
Expand Down
152 changes: 152 additions & 0 deletions tests/vet.bats
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,31 @@ EOF
create_mock "curl" "$script_content"
}

create_downloader_mock() {
local downloader_name="$1"
local fixture_path="$2"
local args_log_file="$3"

local script_content=$(cat <<EOF
echo "\$@" > "${args_log_file}"

output_file=""
while [ "\$#" -gt 0 ]; do
case "\$1" in
-o|--output) output_file="\$2"; shift ;; # curl
-O) output_file="\$2"; shift ;; # wget -qO
esac
shift
done
if [ -n "\$output_file" ]; then
cat '${fixture_path}' > "\$output_file"
fi
exit 0
EOF
)
create_mock "$downloader_name" "$script_content"
}

@test "vet --help shows usage" {
run "$VET_SCRIPT" --help
assert_output --partial "USAGE:"
Expand Down Expand Up @@ -124,3 +149,130 @@ EOF
assert_failure
assert_output --partial "Downloaded file is empty"
}

@test "vet handles --token-stdin when piped" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

run bash -c "(echo 'secret-token'; echo 'y') | ${VET_SCRIPT} --token-stdin http://example.com/script.sh"
assert_success

run grep -q -- "-H Authorization: Bearer secret-token" "$args_log"
assert_success "Expected to find bearer token header in curl args"
}

@test "vet fails when --token-stdin receives no input" {
create_curl_mock "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh"

run ${VET_SCRIPT} --token-stdin http://example.com/script.sh < /dev/null

assert_failure
assert_output --partial "Failed to read a non-empty token from stdin"
}

@test "vet uses VET_AUTH_TOKEN environment variable for authentication" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

export VET_AUTH_TOKEN="env-secret-token"
run bash -c "echo 'y' | ${VET_SCRIPT} http://example.com/script.sh"

assert_success

run grep -q -- "-H Authorization: Bearer env-secret-token" "$args_log"
assert_success "Expected to find VET_AUTH_TOKEN bearer header in curl args"
}

@test "vet handles --netrc flag and shows compatibility warning" {
local args_log="${TEST_DIR}/downloader_args.log"
echo "machine example.com login user password pass" > "${HOME}/.netrc"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

run bash -c "echo 'y' | ${VET_SCRIPT} --netrc http://example.com/script.sh"

assert_success
assert_output --partial "The --netrc flag is often incompatible"
run grep -q -- "-n" "$args_log"
assert_success "Expected to find -n flag in curl args"
}

@test "vet prioritizes --token-stdin over VET_AUTH_TOKEN" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

export VET_AUTH_TOKEN="env-token-should-be-ignored"
run bash -c "(echo 'stdin-token-is-king'; echo 'y') | ${VET_SCRIPT} --token-stdin http://example.com/script.sh"

assert_success

run grep -q -- "-H Authorization: Bearer stdin-token-is-king" "$args_log"
assert_success "Expected stdin token to be used"

run grep -q "env-token-should-be-ignored" "$args_log"
assert_failure "Expected environment token to be ignored"
}

@test "vet prioritizes VET_AUTH_TOKEN over --netrc" {
local args_log="${TEST_DIR}/downloader_args.log"
echo "machine example.com login user password pass" > "${HOME}/.netrc"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

export VET_AUTH_TOKEN="the-real-token"
run bash -c "echo 'y' | ${VET_SCRIPT} --netrc http://example.com/script.sh"

assert_success

run grep -q -- "-H Authorization: Bearer the-real-token" "$args_log"
assert_success "Expected VET_AUTH_TOKEN to be used"

run grep -q -- "-n" "$args_log"
assert_failure "Expected -n flag to be ignored when VET_AUTH_TOKEN is present"
}

@test "vet uses --auth-header with VET_AUTH_TOKEN for custom authentication" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

export VET_AUTH_TOKEN="glpat-abcdef123456"

run "$VET_SCRIPT" --force --auth-header "PRIVATE-TOKEN: {}" http://example.com/gitlab-script.sh

assert_success

run cat "$args_log"
assert_output --partial "-H PRIVATE-TOKEN: glpat-abcdef123456"

refute_output --partial "Bearer"
}

@test "vet handles piped token and confirmation in non-interactive mode" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

run bash -c "(echo 'secret-token'; echo 'y') | ${VET_SCRIPT} --token-stdin http://example.com/script.sh"

assert_success
assert_output --partial "Simple script executed successfully"

run cat "$args_log"
assert_output --partial "-H Authorization: Bearer secret-token"
}


@test "vet switches to keyboard for prompts after piping token" {
local args_log="${TEST_DIR}/downloader_args.log"
create_downloader_mock "curl" "${BATS_TEST_DIRNAME}/fixtures/simple_success.sh" "$args_log"

local keyboard_pipe="${TEST_DIR}/keyboard_pipe"
mkfifo "$keyboard_pipe"

( sleep 0.5 && echo 'y' > "$keyboard_pipe" ) &

run script -q -c "echo 'secret-token' | ${VET_SCRIPT} --token-stdin http://example.com/script.sh" /dev/null < "$keyboard_pipe"

assert_success "Script should succeed after user confirms with 'y'"
assert_output --partial "Simple script executed successfully"

run cat "$args_log"
assert_output --partial "-H Authorization: Bearer secret-token"
}
Loading
Loading