feat: e2e tests within rust instead

This commit is contained in:
Bart van der Braak 2023-11-22 05:17:04 +01:00
parent 7b40a0ae17
commit 38a15a3bcd
8 changed files with 550 additions and 156 deletions

View file

@ -40,7 +40,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- name: Run tests - name: Run tests
run: cargo test --all run: cargo test --bins
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View file

@ -1,153 +0,0 @@
name: Checks
permissions:
id-token: write
contents: read
env:
VAULT_NAME: bvdbkeyweavetweukvt{0}
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build Keyweave
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Build project
run: cargo build --all --release
- uses: actions/upload-artifact@v3.1.3
with:
path: target/release/keyweave
bicep:
name: Deploy Azure resources
environment: bicep
runs-on: ubuntu-latest
env:
LOCATION: eastus
DEPLOYMENT_NAME: keyweave-${{ github.run_id }}
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Deploy Bicep template
uses: azure/arm-deploy@v1
with:
scope: subscription
region: ${{ env.LOCATION }}
template: bicep/main.bicep
deploymentName: ${{ env.DEPLOYMENT_NAME }}
none-test:
name: Tests without access
needs: [build, bicep]
runs-on: ubuntu-latest
environment: none
steps:
- uses: actions/download-artifact@v3.0.2
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Use Keyweave with No Access Policies
run: |
chmod +x ./artifact/keyweave
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}
get-test:
name: Tests with Get access
needs: [build, bicep]
runs-on: ubuntu-latest
environment: get
steps:
- uses: actions/download-artifact@v3.0.2
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Use Keyweave with Only Get Access Policy
run: |
chmod +x ./artifact/keyweave
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}
list-test:
name: Tests with List access
needs: [build, bicep]
runs-on: ubuntu-latest
environment: list
steps:
- uses: actions/download-artifact@v3.0.2
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Use Keyweave with Only List Access Policy
run: |
chmod +x ./artifact/keyweave
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}
get-list-test:
name: Tests with Get and List access
needs: [build, bicep]
runs-on: ubuntu-latest
environment: getlist
steps:
- uses: actions/download-artifact@v3.0.2
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Use Keyweave with both Get and List Access Policies
run: |
chmod +x ./artifact/keyweave
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}
- name: Use Keyweave with a filter
run: |
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }} --filter "filter"
- name: Use Keyweave with a complex file path
run: |
mkdir -p "user/projects/project 1/src/lib"
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }} --output "user/projects/project 1/src/lib/.env"
- name: Use Keyweave with a non-existent Key Vault
run: ./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}1234
- name: Use Keyweave with a firewalled Key Vault
run: ./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '2') }}
- name: Use Keyweave with a no permissions
run: |
mkdir -p "user/projects/project 1/src/lib"
./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }} --output "/.env"
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.OTHER_SUBSCRIPTION_ID }}
- name: Use Keyweave while logged into other Subscription
run: ./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}
# - uses: azure/login@v1
# with:
# client-id: ${{ secrets.AZURE_CLIENT_ID }}
# tenant-id: ${{ secrets.OTHER_TENANT_ID }}
# subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# - name: Use Keyweave while logged into other Azure Tenant
# run: ./artifact/keyweave --vault-name ${{ format(env.VAULT_NAME, '1') }}

45
.github/workflows/tests.yml vendored Normal file
View file

@ -0,0 +1,45 @@
name: Tests
permissions:
id-token: write
contents: read
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
bicep:
name: Deploy Azure resources
environment: bicep
runs-on: ubuntu-latest
env:
LOCATION: eastus
DEPLOYMENT_NAME: keyweave-${{ github.run_id }}
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Deploy Bicep template
uses: azure/arm-deploy@v1
with:
scope: subscription
region: ${{ env.LOCATION }}
template: bicep/main.bicep
deploymentName: ${{ env.DEPLOYMENT_NAME }}
test:
name: Tests
needs: bicep
runs-on: ubuntu-latest
environment: test
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Run all tests
run: cargo test --all

297
Cargo.lock generated
View file

@ -17,6 +17,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@ -86,6 +95,36 @@ version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "assert_cmd"
version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
dependencies = [
"anstyle",
"bstr",
"doc-comment",
"predicates",
"predicates-core",
"predicates-tree",
"wait-timeout",
]
[[package]]
name = "assert_fs"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f070617a68e5c2ed5d06ee8dd620ee18fb72b99f6c094bed34cf8ab07c875b48"
dependencies = [
"anstyle",
"doc-comment",
"globwalk",
"predicates",
"predicates-core",
"predicates-tree",
"tempfile",
]
[[package]] [[package]]
name = "async-channel" name = "async-channel"
version = "1.9.0" version = "1.9.0"
@ -235,6 +274,17 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "bstr"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.14.0"
@ -382,6 +432,19 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.2",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.3.9" version = "0.3.9"
@ -392,6 +455,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@ -402,12 +471,24 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "dyn-clone" name = "dyn-clone"
version = "1.0.16" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d"
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.33" version = "0.8.33"
@ -469,6 +550,15 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -643,6 +733,30 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "globset"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
dependencies = [
"aho-corasick",
"bstr",
"fnv",
"log",
"regex",
]
[[package]]
name = "globwalk"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
dependencies = [
"bitflags 1.3.2",
"ignore",
"walkdir",
]
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.21" version = "0.3.21"
@ -668,6 +782,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.4.1"
@ -804,6 +924,23 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "ignore"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
dependencies = [
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
"thread_local",
"walkdir",
"winapi-util",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.3" version = "1.9.3"
@ -811,7 +948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown 0.12.3",
] ]
[[package]] [[package]]
@ -835,6 +972,15 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.9" version = "1.0.9"
@ -855,12 +1001,17 @@ name = "keyweave"
version = "0.2.3" version = "0.2.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd",
"assert_fs",
"azure_core",
"azure_identity", "azure_identity",
"azure_security_keyvault", "azure_security_keyvault",
"clap", "clap",
"futures", "futures",
"openssl", "openssl",
"paris", "paris",
"predicates",
"serial_test",
"tokio", "tokio",
] ]
@ -948,6 +1099,12 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.17" version = "0.2.17"
@ -1161,6 +1318,37 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "predicates"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0"
dependencies = [
"anstyle",
"difflib",
"float-cmp",
"itertools",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]]
name = "predicates-core"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
[[package]]
name = "predicates-tree"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
dependencies = [
"predicates-core",
"termtree",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.69" version = "1.0.69"
@ -1259,6 +1447,35 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.22" version = "0.11.22"
@ -1333,6 +1550,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.22" version = "0.1.22"
@ -1441,6 +1667,31 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serial_test"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d"
dependencies = [
"dashmap",
"futures",
"lazy_static",
"log",
"parking_lot",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.8" version = "0.10.8"
@ -1547,6 +1798,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "termtree"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.50" version = "1.0.50"
@ -1567,6 +1824,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.30" version = "0.3.30"
@ -1774,12 +2041,31 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "waker-fn" name = "waker-fn"
version = "1.1.1" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
[[package]]
name = "walkdir"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@ -1906,6 +2192,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View file

@ -11,6 +11,7 @@ repository = "https://github.com/bartvdbraak/keyweave/"
[dependencies] [dependencies]
anyhow = "1.0.75" anyhow = "1.0.75"
azure_core = "0.17.0"
azure_identity = "0.17.0" azure_identity = "0.17.0"
azure_security_keyvault = "0.17.0" azure_security_keyvault = "0.17.0"
clap = { version = "4.4.8", features = ["derive"] } clap = { version = "4.4.8", features = ["derive"] }
@ -20,3 +21,9 @@ tokio = {version = "1.34.0", features = ["full"]}
[target.'cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "arm", target_arch = "aarch64")))'.dependencies] [target.'cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "arm", target_arch = "aarch64")))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] } openssl = { version = "0.10", features = ["vendored"] }
[dev-dependencies]
assert_cmd = "2.0.12"
assert_fs = "1.0.13"
predicates = "3.0.4"
serial_test = "2.0.0"

View file

@ -20,7 +20,7 @@ resource federatedCredential 'Microsoft.ManagedIdentity/userAssignedIdentities/f
parent: managedIdentity[index] parent: managedIdentity[index]
properties: { properties: {
issuer: 'https://token.actions.githubusercontent.com' issuer: 'https://token.actions.githubusercontent.com'
subject: 'repo:bartvdbraak/keyweave:environment:${environment}' subject: 'repo:bartvdbraak/keyweave:environment:test'
audiences: [ audiences: [
'api://AzureADTokenExchange' 'api://AzureADTokenExchange'
] ]

View file

@ -11,6 +11,7 @@ use std::io::Write;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use azure_core::error::HttpError;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)] #[clap(author, version, about, long_about = None)]
@ -59,6 +60,15 @@ async fn fetch_secrets_from_key_vault(
Err(err) => { Err(err) => {
log!("\n"); log!("\n");
error!("Failed to fetch secrets page: {}", err); error!("Failed to fetch secrets page: {}", err);
let specific_error = err.downcast_ref::<HttpError>();
if let Some(specific_error) = specific_error {
// Check the contents of the specific error
if specific_error.error_message().unwrap().to_string().contains("does not have secrets list permission on key vault") {
info!("Make sure you have List permissions on the Key Vault.");
} else if specific_error.error_message().unwrap().to_string().contains("is not authorized and caller is not a trusted service") {
info!("Make sure you're on the Key Vaults Firewall allowlist.");
}
}
return Err(err.into()); return Err(err.into());
} }
}; };
@ -69,6 +79,7 @@ async fn fetch_secrets_from_key_vault(
Ok(secret_values) Ok(secret_values)
} }
async fn fetch_secrets_from_page( async fn fetch_secrets_from_page(
client: &azure_security_keyvault::SecretClient, client: &azure_security_keyvault::SecretClient,
page: &KeyVaultGetSecretsResponse, page: &KeyVaultGetSecretsResponse,
@ -127,6 +138,7 @@ async fn fetch_and_send_secret(
} }
Err(err) => { Err(err) => {
error!("Error fetching secret: {}", err); error!("Error fetching secret: {}", err);
info!("Make sure you have Get permissions on the Key Vault.");
(secret_id, String::new()) (secret_id, String::new())
} }
} }

188
tests/e2e.rs Normal file
View file

@ -0,0 +1,188 @@
use assert_cmd::prelude::*;
use assert_fs::prelude::*;
use assert_fs::TempDir;
use std::process::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::env;
static BINARY: &str = "keyweave";
static KEYVAULT: &str = "bvdbkeyweavetweukvt1";
static FIREWALL_KEYVAULT: &str = "bvdbkeyweavetweukvt2";
static NON_EXISTENT_KEYVAULT: &str = "bvdbkeyweavetweukvt3";
fn azure_cli_login(client_id: String, tenant_id: String, subscription_id: String) -> Result<(), std::io::Error> {
Command::new("az")
.arg("login")
.arg("--identity")
.arg("--username")
.arg(client_id)
.arg("--tenant")
.arg(tenant_id)
.output()?;
Command::new("az")
.arg("account")
.arg("set")
.arg("--subscription")
.arg(subscription_id)
.output()?;
Ok(())
}
/// Test with no access policies - expected to fail.
#[tokio::test]
#[serial]
async fn test_no_access_policies() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_NO_ACCESS").expect("Failed to get AZURE_CLIENT_ID_NO_ACCESS"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().failure().stderr(predicate::str::contains("Make sure you have List permissions on the Key Vault."));
temp_dir.close().unwrap();
}
/// Test with only Get access policy - expected to fail.
#[tokio::test]
#[serial]
async fn test_only_get_access_policy() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_GET").expect("Failed to get AZURE_CLIENT_ID_GET"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().failure().stderr(predicate::str::contains("Make sure you have List permissions on the Key Vault."));
temp_dir.close().unwrap();
}
/// Test with only List access policy - expected to succeed with get errors.
#[tokio::test]
#[serial]
async fn test_only_list_access_policy() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_LIST").expect("Failed to get AZURE_CLIENT_ID_LIST"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().success().stderr(predicate::str::contains("Make sure you have Get permissions on the Key Vault."));
temp_dir.close().unwrap();
}
/// Test with both Get and List access policies - expected to pass.
#[tokio::test]
#[serial]
async fn test_get_and_list_access_policies() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_GET_LIST").expect("Failed to get AZURE_CLIENT_ID_GET_LIST"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().success();
output_path.assert(predicate::path::is_file());
output_path.assert(predicate::str::contains("testSecret=testSecretValue"));
output_path.assert(predicate::str::contains("filterTestSecret=filterTestSecretValue"));
temp_dir.close().unwrap();
}
/// Test with both Get and List access policies and filter - expected to pass.
#[tokio::test]
#[serial]
async fn test_get_and_list_access_policies_filter() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_GET_LIST").expect("Failed to get AZURE_CLIENT_ID_GET_LIST"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(KEYVAULT)
.arg("--output").arg(output_path.path())
.arg("--filter").arg("filter");
cmd.assert().success();
output_path.assert(predicate::path::is_file());
output_path.assert(predicate::str::contains("filterTestSecret=filterTestSecretValue"));
temp_dir.close().unwrap();
}
/// Test with both Get and List access policies on a Key Vault with Firewall - expected to fail.
#[tokio::test]
#[serial]
async fn test_get_and_list_access_policies_firewall() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_GET_LIST").expect("Failed to get AZURE_CLIENT_ID_GET_LIST"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(FIREWALL_KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().failure().stderr(predicate::str::contains("Make sure you're on the Key Vaults Firewall allowlist."));
temp_dir.close().unwrap();
}
/// Test with both Get and List access policies on a non-existent Key Vault - expected to fail.
#[tokio::test]
#[serial]
async fn test_get_and_list_access_policies_non_existent() {
azure_cli_login(
env::var("AZURE_CLIENT_ID_GET_LIST").expect("Failed to get AZURE_CLIENT_ID_GET_LIST"),
env::var("AZURE_TENANT_ID").expect("Failed to get AZURE_TENANT_ID"),
env::var("AZURE_SUBSCRIPTION_ID").expect("Failed to get AZURE_SUBSCRIPTION_ID"),
).expect("Failed to log in to Azure CLI");
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.child(".env");
let mut cmd = Command::cargo_bin(BINARY).unwrap();
cmd.arg("--vault-name").arg(NON_EXISTENT_KEYVAULT)
.arg("--output").arg(output_path.path());
cmd.assert().failure().stderr(predicate::str::contains("Please check that the Key Vault exists or that you have no connectivity issues."));
temp_dir.close().unwrap();
}