diff --git a/.circleci/config.yml b/.circleci/config.yml
index 4408c6e..ac91a2a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -5,18 +5,56 @@ jobs:
- image: circleci/golang:1.12
steps:
- checkout
+ - run: mkdir -p workspace/plugins workspace/coverage
- run:
name: Build
command: |
- go build -o bin/vault-plugin-secrets-artifactory .
- - run:
- name: Create directory for artifacts
- command: |
- mkdir -p /tmp/artifacts
+ mkdir -p workspace/plugins
+ go build -a -ldflags '-linkmode external -extldflags "-static"' -o workspace/plugins/artifactory ./cmd/vault-plugin-secrets-artifactory
+ - persist_to_workspace:
+ root: workspace
+ paths:
+ - plugins
- run:
name: Unit tests
command: |
go test -cover -coverprofile=coverage.out -v ./...
- go tool cover -html=coverage.out -o /tmp/artifacts/coverage.html
+ go tool cover -html=coverage.out -o workspace/coverage/coverage.html
+ - store_artifacts:
+ path: workspace
+
+ integration:
+ docker:
+ - image: vault:1.2.1
+ environment:
+ ARTIFACTORY_URL: http://localhost:8081/artifactory
+ VAULT_ADDR: http://127.0.0.1:8200
+ VAULT_TOKEN: root-token
+ VAULT_PLUGIN_DIR: workspace/plugins
+ VAULT_LOG_DIR: workspace/integration
+ - image: docker.bintray.io/jfrog/artifactory-oss:latest
+ environment:
+ ARTIFACTORY_MASTER_KEY: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ steps:
+ - checkout
+ - attach_workspace:
+ at: workspace
+ - run:
+ name: Install dependencies
+ command: |
+ apk add --update --no-cache bash curl
+ - run:
+ name: Integration tests
+ command: |
+ ./integration/test.sh
- store_artifacts:
- path: /tmp/artifacts
+ path: workspace
+
+workflows:
+ version: 2
+ build-and-test:
+ jobs:
+ - build
+ - integration:
+ requires:
+ - build
diff --git a/integration/artifactory.config.xml b/integration/artifactory.config.xml
new file mode 100644
index 0000000..ba3f0cf
--- /dev/null
+++ b/integration/artifactory.config.xml
@@ -0,0 +1,269 @@
+
+
+ false
+ true
+ 100
+ 11
+ dd-MM-yy HH:mm:ss z
+
+ true
+ 1565407695531
+
+
+ true
+ false
+
+ supported
+
+ false
+ 60
+ true
+
+
+ true
+ 3
+ 60
+
+
+
+
+
+ false
+ 5
+
+
+ false
+ false
+
+
+
+ backup-daily
+ true
+ 0 0 2 ? * MON-FRI
+ 0
+ false
+
+ true
+ false
+ false
+
+
+ backup-weekly
+ false
+ 0 0 2 ? * SAT
+ 336
+ false
+
+ true
+ false
+ false
+
+
+
+ false
+ 0 23 5 * * ?
+
+
+
+ artifactory-build-info
+ buildinfo
+ Build Info repository
+ **/*
+ simple-default
+ V2
+ false
+ false
+ true
+ true
+ 0
+ 0
+ true
+
+ false
+ unique
+ client-checksums
+ false
+ 0
+ false
+ false
+
+
+ local
+ generic
+ **/*
+ simple-default
+ V2
+ false
+ false
+ true
+ true
+ 0
+ 0
+ true
+
+ false
+ unique
+ client-checksums
+ false
+ 0
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+ maven-2-default
+ [orgPath]/[module]/[baseRev](-[folderItegRev])/[module]-[baseRev](-[fileItegRev])(-[classifier]).[ext]
+ true
+ [orgPath]/[module]/[baseRev](-[folderItegRev])/[module]-[baseRev](-[fileItegRev])(-[classifier]).pom
+ SNAPSHOT
+ SNAPSHOT|(?:(?:[0-9]{8}.[0-9]{6})-(?:[0-9]+))
+
+
+ ivy-default
+ [org]/[module]/[baseRev](-[folderItegRev])/[type]s/[module](-[classifier])-[baseRev](-[fileItegRev]).[ext]
+ true
+ [org]/[module]/[baseRev](-[folderItegRev])/[type]s/ivy-[baseRev](-[fileItegRev]).xml
+ \d{14}
+ \d{14}
+
+
+ gradle-default
+ [org]/[module]/[baseRev](-[folderItegRev])/[module]-[baseRev](-[fileItegRev])(-[classifier]).[ext]
+ true
+ [org]/[module]/ivy-[baseRev](-[fileItegRev]).xml
+ \d{14}
+ \d{14}
+
+
+ maven-1-default
+ [org]/[type]s/[module]-[baseRev](-[fileItegRev])(-[classifier]).[ext]
+ true
+ [org]/[type]s/[module]-[baseRev](-[fileItegRev]).pom
+ .+
+ .+
+
+
+ nuget-default
+ [orgPath]/[module]/[module].[baseRev](-[fileItegRev]).nupkg
+ false
+ .*
+ .*
+
+
+ npm-default
+ [orgPath]/[module]/[module]-[baseRev](-[fileItegRev]).tgz
+ false
+ .*
+ .*
+
+
+ bower-default
+ [orgPath]/[module]/[module]-[baseRev](-[fileItegRev]).[ext]
+ false
+ .*
+ .*
+
+
+ vcs-default
+ [orgPath]/[module]/[refs<tags|branches>]/[baseRev]/[module]-[baseRev](-[fileItegRev])(-[classifier]).[ext]
+ false
+ .*
+ [a-zA-Z0-9]{40}
+
+
+ sbt-default
+ [org]/[module]/(scala_[scalaVersion<.+>])/(sbt_[sbtVersion<.+>])/[baseRev]/[type]s/[module](-[classifier]).[ext]
+ true
+ [org]/[module]/(scala_[scalaVersion<.+>])/(sbt_[sbtVersion<.+>])/[baseRev]/[type]s/ivy.xml
+ \d{14}
+ \d{14}
+
+
+ simple-default
+ [orgPath]/[module]/[module]-[baseRev].[ext]
+ false
+ .*
+ .*
+
+
+ composer-default
+ [orgPath]/[module]/[module]-[baseRev](-[fileItegRev]).[ext]
+ false
+ .*
+ .*
+
+
+ conan-default
+ [org]/[module]/[baseRev]/[channel<[^/]+>]/[folderItegRev]/(package/[package_id<[^/]+>]/[fileItegRev]/)?[remainder<(?:.+)>]
+ false
+ [^/]+
+ [^/]+
+
+
+ puppet-default
+ [orgPath]/[module]/[orgPath]-[module]-[baseRev].tar.gz
+ false
+ .*
+ .*
+
+
+ go-default
+ [orgPath]/[module]/@v/v[refs].zip
+ false
+ .*
+ .*
+
+
+ build-default
+ [orgPath]/[module](-[fileItegRev]).[ext]
+ false
+ .*
+ .*
+
+
+
+
+
+ 0 0 /4 * * ?
+
+
+ 0 12 5 * * ?
+
+
+ 0 12 0 * * ?
+
+
+ false
+ false
+ 1024
+ 5000
+ 10
+
+
+ true
+ false
+ 14
+
+
+ false
+ false
+
+
+
+ false
+
+
+ 720
+
+
+ 31536000
+
+
diff --git a/integration/artifactory.security.xml b/integration/artifactory.security.xml
new file mode 100644
index 0000000..3977906
--- /dev/null
+++ b/integration/artifactory.security.xml
@@ -0,0 +1,122 @@
+
+
+
+
+ anonymous
+ false
+ true
+ false
+ true
+ false
+ true
+ true
+ internal
+ false
+
+
+ 0
+ 0
+ false
+
+
+ admin
+ bcrypt$$2a$08$ww3xUFAUw4eOgASvYc3O6e9tNgtNa5G4qHpXvWMpwwcGxiEu2UM..
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ internal
+ false
+
+
+ 1565410034560
+ 172.17.0.1
+ 0
+ false
+
+
+ access-admin
+ bcrypt$$2a$08$MNZh9xfCw0FYF.hPNKtjAuAaXKOotl.kQcH6QbyW186Ovmzewqq.m
+ false
+ true
+ false
+ true
+ false
+ true
+ true
+ internal
+ false
+
+
+ 0
+ 0
+ false
+
+
+
+
+ readers
+ A group for read-only users
+ true
+ internal
+ false
+
+
+ writers
+ Able to write to any repository
+ false
+ internal
+ false
+
+
+
+
+
+
+ readers
+ true
+ 1
+
+
+ admin
+ 1565411163416
+ jfrt@01dhwtj1th5w3a1r4aja62177e:72d32801-6fd9-4f98-afa2-18d555f98d08
+
+ readers
+
+ **
+
+
+
+ ANY LOCAL
+
+
+
+
+
+
+ writers
+ true
+ 14
+
+
+ admin
+ 1565411138117
+ jfrt@01dhwtj1th5w3a1r4aja62177e:236c3bd1-1a0a-4a4b-9b5b-d03e6b7f115d
+
+ writers
+
+ **
+
+
+
+ ANY LOCAL
+
+
+
+
+
+
\ No newline at end of file
diff --git a/integration/test.sh b/integration/test.sh
new file mode 100755
index 0000000..3492c30
--- /dev/null
+++ b/integration/test.sh
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+function fail {
+ echo $1 >&2
+ exit 1
+}
+
+function retry {
+ local n=1
+ local max=15
+ local delay=15
+ echo -n "Waiting for $@ to succeed"
+ while true; do
+ "$@" >/dev/null 2>&1 && break || {
+ if [[ $n -lt $max ]]; then
+ ((n++))
+ echo -n "."
+ sleep $delay;
+ else
+ fail " FAILED after $n attempts!"
+ fi
+ }
+ done
+ echo " OK!"
+}
+
+function cleanup {
+ kill "${vault_pid}"
+}
+trap cleanup EXIT
+
+mkdir -p "${VAULT_LOG_DIR}"
+vault server \
+ -dev \
+ -dev-plugin-dir="${VAULT_PLUGIN_DIR}" \
+ -dev-plugin-init \
+ -dev-root-token-id="${VAULT_TOKEN}" \
+ -log-level=trace \
+ > "${VAULT_LOG_DIR}/vault.log" 2>&1 &
+vault_pid=$!
+
+retry vault status
+
+vault secrets enable \
+ -path=artifactory \
+ -plugin-name=artifactory \
+ plugin
+
+retry curl -fsS "${ARTIFACTORY_URL}/api/system/ping"
+
+echo "Artifactory system/configuration:"
+curl \
+ -fsS \
+ -u admin:password \
+ -X POST \
+ -H "Content-type: application/xml" \
+ --data-binary @integration/artifactory.config.xml \
+ "${ARTIFACTORY_URL}/api/system/configuration"
+echo ""
+
+echo "Artifactory system/security:"
+curl \
+ -fsS \
+ -u admin:password \
+ -X POST \
+ -H "Content-type: application/xml" \
+ --data-binary @integration/artifactory.security.xml \
+ "${ARTIFACTORY_URL}/api/system/security"
+echo ""
+
+vault write artifactory/config \
+ address="${ARTIFACTORY_URL}" \
+ tls_verify=false \
+ username=admin \
+ password=password
+
+vault write artifactory/roles/writer \
+ member_of_groups=writers \
+ username=vault-user-writer \
+ ttl=600
+WRITER_ACCESS_TOKEN="$(vault read -field=access_token artifactory/token/writer)"
+
+vault write artifactory/roles/reader \
+ member_of_groups=readers \
+ username=vault-user-reader \
+ ttl=600
+READER_ACCESS_TOKEN="$(vault read -field=access_token artifactory/token/reader)"
+
+echo -n "Verify writer can deploy artifact to local repository: "
+if ! curl -fs -o /dev/null -X PUT -T "$0" -H "Authorization: Bearer ${WRITER_ACCESS_TOKEN}" "${ARTIFACTORY_URL}/local/artifact"
+then
+ echo "ERROR: writer role was unable to deploy an artifact"
+ exit 1
+fi
+echo "SUCCESS!"
+
+echo -n "Verify reader cannot deploy artifact to local repository: "
+if curl -fs -X PUT -T "$0" -H "Authorization: Bearer ${READER_ACCESS_TOKEN}" "${ARTIFACTORY_URL}/local/artifact"
+then
+ echo "ERROR: reader should not be able to deploy artifact!"
+ exit 1
+fi
+echo "SUCCESS!"
+
+echo -n "Verify reader can read artifact: "
+if ! curl -fs -o /dev/null -H "Authorization: Bearer ${READER_ACCESS_TOKEN}" "${ARTIFACTORY_URL}/local/artifact"
+then
+ echo "ERROR: reader role was unable to read an artifact"
+ exit 1
+fi
+echo "SUCCESS!"
+
+echo -n "Verify writer cannot read artifact: "
+if curl -fs -o /dev/null -H "Authorization: Bearer ${WRITER_ACCESS_TOKEN}" "${ARTIFACTORY_URL}/local/artifact"
+then
+ echo "ERROR: writer should not be able to read artifact!"
+ exit 1
+fi
+echo "SUCCESS!"