Compare commits

..

1 Commits

Author SHA1 Message Date
Don 1b71fe6cdd Update Windows Dockerfiles 2020-10-14 07:24:18 -07:00
76 changed files with 1974 additions and 4707 deletions
+50
View File
@@ -0,0 +1,50 @@
local pipeline = import 'pipeline.libsonnet';
[
pipeline.test('linux', 'amd64'),
pipeline.build('docker', 'linux', 'amd64'),
pipeline.build('docker', 'linux', 'arm64'),
pipeline.build('docker', 'linux', 'arm'),
pipeline.notifications('docker', depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
]),
pipeline.build('gcr', 'linux', 'amd64'),
pipeline.build('gcr', 'linux', 'arm64'),
pipeline.build('gcr', 'linux', 'arm'),
pipeline.notifications('gcr', depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
]),
pipeline.build('acr', 'linux', 'amd64'),
pipeline.build('acr', 'linux', 'arm64'),
pipeline.build('acr', 'linux', 'arm'),
pipeline.notifications('acr', depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
]),
pipeline.build('ecr', 'linux', 'amd64'),
pipeline.build('ecr', 'linux', 'arm64'),
pipeline.build('ecr', 'linux', 'arm'),
pipeline.notifications('ecr', depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
]),
pipeline.build('heroku', 'linux', 'amd64'),
pipeline.build('heroku', 'linux', 'arm64'),
pipeline.build('heroku', 'linux', 'arm'),
pipeline.notifications('heroku', depends_on=[
'linux-amd64',
'linux-arm64',
'linux-arm',
]),
]
+1280 -912
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
since-tag=v19.03.8
-2
View File
@@ -1,5 +1,3 @@
release release
coverage.out coverage.out
vendor vendor
.vscode/
Dockerfile
-15
View File
@@ -1,15 +0,0 @@
inputSet:
name: event-PR
tags: {}
identifier: eventPR
orgIdentifier: default
projectIdentifier: Drone_Plugins
pipeline:
identifier: dronedockerharness
properties:
ci:
codebase:
build:
type: PR
spec:
number: <+trigger.prNumber>
-15
View File
@@ -1,15 +0,0 @@
inputSet:
name: event-Push
tags: {}
identifier: eventPush
orgIdentifier: default
projectIdentifier: Drone_Plugins
pipeline:
identifier: dronedockerharness
properties:
ci:
codebase:
build:
type: branch
spec:
branch: <+trigger.branch>
-15
View File
@@ -1,15 +0,0 @@
inputSet:
name: event-Tag
tags: {}
identifier: eventTag
orgIdentifier: default
projectIdentifier: Drone_Plugins
pipeline:
identifier: dronedockerharness
properties:
ci:
codebase:
build:
type: tag
spec:
tag: <+trigger.tag>
-447
View File
@@ -1,447 +0,0 @@
pipeline:
orgIdentifier: default
tags: {}
properties:
ci:
codebase:
connectorRef: GitHub_Drone_Plugins_Org
repoName: drone-docker
build: <+input>
sparseCheckout: []
stages:
- stage:
name: Test
identifier: Test
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: false
paths: []
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: GO VET
identifier: Run_1
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: go vet ./...
- step:
type: Run
name: GO TEST
identifier: Run_2
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: go test -cover ./...
- parallel:
- stage:
name: linux-amd64
identifier: linamd64
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: false
paths: []
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: Build Binary
identifier: Build_Push
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: go build -a -tags netgo -o release/linux/amd64/drone-<+matrix.repo> ./cmd/drone-<+matrix.repo>
envVariables:
CGO_ENABLED: "0"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- step:
type: Plugin
name: Build and Push on Tag
identifier: Docker_Build_and_Push
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: plugins/docker
settings:
username: drone
password: <+secrets.getValue("Plugins_Docker_Hub_Pat")>
repo: plugins/<+matrix.repo>
dockerfile: docker/<+matrix.repo>/Dockerfile.linux.amd64
auto_tag: "true"
auto_tag_suffix: linux-amd64
when:
stageStatus: Success
condition: <+codebase.build.type> == "tag"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- step:
type: BuildAndPushDockerRegistry
name: Build and Push on Branch
identifier: BuildAndPushDockerRegistry_1
spec:
connectorRef: Plugins_Docker_Hub_Connector
repo: plugins/<+matrix.repo>
tags:
- linux-amd64
caching: false
dockerfile: docker/<+matrix.repo>/Dockerfile.linux.amd64
when:
stageStatus: Success
condition: <+codebase.build.type> == "branch"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- stage:
name: linux-arm64
identifier: linarm64
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: false
paths: []
platform:
os: Linux
arch: Arm64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: Build Binary
identifier: buildpush
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: go build -a -tags netgo -o release/linux/arm64/drone-<+matrix.repo> ./cmd/drone-<+matrix.repo>
envVariables:
CGO_ENABLED: "0"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- step:
type: Plugin
name: Build and Push on Tag
identifier: Docker_Build_and_Push
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: plugins/docker
settings:
username: drone
password: <+secrets.getValue("Plugins_Docker_Hub_Pat")>
repo: plugins/<+matrix.repo>
dockerfile: docker/<+matrix.repo>/Dockerfile.linux.arm64
auto_tag: "true"
auto_tag_suffix: linux-arm64
when:
stageStatus: Success
condition: <+codebase.build.type> == "tag"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- step:
type: BuildAndPushDockerRegistry
name: Build and Push on Branch
identifier: BuildAndPushDockerRegistry_1
spec:
connectorRef: Plugins_Docker_Hub_Connector
repo: plugins/<+matrix.repo>
tags:
- linux-arm64
caching: false
dockerfile: docker/<+matrix.repo>/Dockerfile.linux.arm64
when:
stageStatus: Success
condition: <+codebase.build.type> == "branch"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
- stage:
name: win-1809-amd64
identifier: win1809amd64
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: true
infrastructure:
type: VM
spec:
type: Pool
spec:
poolName: windows-2019
os: Windows
execution:
steps:
- step:
type: Run
name: Build Binary
identifier: go_build
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: |-
# disable cgo
export CGO_ENABLED=0
go build -o release/windows/amd64/drone-<+matrix.repo>.exe ./cmd/drone-<+matrix.repo>
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
- step:
type: Plugin
name: Build and Push on Tag
identifier: Docker_Build_and_Push1
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: plugins/docker
settings:
username: drone
password: <+secrets.getValue("Plugins_Docker_Hub_Pat")>
repo: plugins/<+matrix.repo>
dockerfile: docker/<+matrix.repo>/Dockerfile.windows.amd64.1809
auto_tag: "true"
auto_tag_suffix: windows-1809-amd64
when:
stageStatus: Success
condition: <+codebase.build.type> == "tag"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
- step:
type: BuildAndPushDockerRegistry
name: Build and Push on Branch
identifier: BuildAndPushDockerRegistry_2
spec:
connectorRef: Plugins_Docker_Hub_Connector
repo: plugins/<+matrix.repo>
tags:
- windows-1809-amd64
caching: false
dockerfile: docker/<+matrix.repo>/Dockerfile.windows.amd64.1809
when:
stageStatus: Success
condition: <+codebase.build.type> == "branch"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
delegateSelectors:
- windows-vm
- stage:
name: win-ltsc2022-amd64
identifier: winamd64
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: false
paths: []
platform:
os: Windows
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: Build Binary -ltsc2022
identifier: build_amd64ltsc2022
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: golang:1.23.0
shell: Sh
command: |-
# disable cgo
export CGO_ENABLED=0
go build -o release/windows/amd64/drone-<+matrix.repo>.exe ./cmd/drone-<+matrix.repo>
envVariables:
CGO_ENABLED: "0"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
- step:
type: Plugin
name: Build and Push on Tag
identifier: Docker_Build_and_Push1
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: plugins/docker
settings:
username: drone
password: <+secrets.getValue("Plugins_Docker_Hub_Pat")>
repo: plugins/<+matrix.repo>
dockerfile: docker/<+matrix.repo>/Dockerfile.windows.amd64.ltsc2022
auto_tag: "true"
auto_tag_suffix: windows-ltsc2022-amd64
when:
stageStatus: Success
condition: <+codebase.build.type> == "tag"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
- step:
type: BuildAndPushDockerRegistry
name: Build and Push on Branch
identifier: BuildAndPushDockerRegistry_2
spec:
connectorRef: Plugins_Docker_Hub_Connector
repo: plugins/<+matrix.repo>
tags:
- windows-ltsc2022-amd64
caching: false
dockerfile: docker/<+matrix.repo>/Dockerfile.windows.amd64.ltsc2022
when:
stageStatus: Success
condition: <+codebase.build.type> == "branch"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- acr
buildIntelligence:
enabled: false
- stage:
name: Manifest and Release
identifier: Manifest
description: ""
type: CI
spec:
cloneCodebase: true
caching:
enabled: false
paths: []
execution:
steps:
- step:
type: Plugin
name: Manifest
identifier: Plugin_1
spec:
connectorRef: Plugins_Docker_Hub_Connector
image: plugins/manifest
settings:
username: drone
password: <+secrets.getValue("Plugins_Docker_Hub_Pat")>
auto_tag: "true"
ignore_missing: "true"
spec: docker/<+matrix.repo>/manifest.tmpl
when:
stageStatus: Success
condition: <+codebase.build.type> == "tag"
strategy:
matrix:
repo:
- docker
- gcr
- gar
- ecr
- heroku
- acr
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
identifier: dronedockerharness
projectIdentifier: Drone_Plugins
name: drone-docker-harness
allowStageExecutions: true
-181
View File
@@ -1,181 +0,0 @@
# Changelog
## [v20.14.5](https://github.com/drone-plugins/drone-docker/tree/v20.14.5) (2023-09-13)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.14.4...v20.14.5)
**Implemented enhancements:**
- Allow gcr authentication with workload identity [\#383](https://github.com/drone-plugins/drone-docker/pull/383) ([dhpollack](https://github.com/dhpollack))
**Fixed bugs:**
- \[fix\]: \[ci-9254\]: go version upgrade to 1.21 [\#401](https://github.com/drone-plugins/drone-docker/pull/401) ([abhay084](https://github.com/abhay084))
- Revert "Add support for AAD auth for docker-acr" [\#398](https://github.com/drone-plugins/drone-docker/pull/398) ([tphoney](https://github.com/tphoney))
**Closed issues:**
- Remove deprecated support of label-schema in favor of OCI [\#396](https://github.com/drone-plugins/drone-docker/issues/396)
**Merged pull requests:**
- Add support for AAD auth for docker-acr [\#395](https://github.com/drone-plugins/drone-docker/pull/395) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness))
## [v20.14.4](https://github.com/drone-plugins/drone-docker/tree/v20.14.4) (2023-05-16)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.14.3...v20.14.4)
**Fixed bugs:**
- fix: Use unique build name for build and tag [\#390](https://github.com/drone-plugins/drone-docker/pull/390) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness))
**Merged pull requests:**
- v20.14.4 prep [\#391](https://github.com/drone-plugins/drone-docker/pull/391) ([rutvijmehta-harness](https://github.com/rutvijmehta-harness))
## [v20.14.3](https://github.com/drone-plugins/drone-docker/tree/v20.14.3) (2023-05-04)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.14.2...v20.14.3)
**Merged pull requests:**
- Write artifacts to input artifact file [\#389](https://github.com/drone-plugins/drone-docker/pull/389) ([raghavharness](https://github.com/raghavharness))
## [v20.14.2](https://github.com/drone-plugins/drone-docker/tree/v20.14.2) (2023-04-18)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.14.1...v20.14.2)
**Merged pull requests:**
- fix windows drone yml [\#388](https://github.com/drone-plugins/drone-docker/pull/388) ([shubham149](https://github.com/shubham149))
## [v20.14.1](https://github.com/drone-plugins/drone-docker/tree/v20.14.1) (2023-01-30)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.14.0...v20.14.1)
**Implemented enhancements:**
- Add option to mount host ssh agent \(--ssh\) [\#382](https://github.com/drone-plugins/drone-docker/pull/382) ([tphoney](https://github.com/tphoney))
**Fixed bugs:**
- windows 1809 docker build pin [\#384](https://github.com/drone-plugins/drone-docker/pull/384) ([tphoney](https://github.com/tphoney))
- \(maint\) move to harness.drone.io [\#381](https://github.com/drone-plugins/drone-docker/pull/381) ([tphoney](https://github.com/tphoney))
## [v20.14.0](https://github.com/drone-plugins/drone-docker/tree/v20.14.0) (2022-11-17)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.13.0...v20.14.0)
**Implemented enhancements:**
- Add support for docker --platform flag [\#376](https://github.com/drone-plugins/drone-docker/pull/376) ([tphoney](https://github.com/tphoney))
**Fixed bugs:**
- Use full path to docker when creating card [\#373](https://github.com/drone-plugins/drone-docker/pull/373) ([donny-dont](https://github.com/donny-dont))
**Merged pull requests:**
- \(maint\) prep for v20.14.0 [\#377](https://github.com/drone-plugins/drone-docker/pull/377) ([tphoney](https://github.com/tphoney))
## [v20.13.0](https://github.com/drone-plugins/drone-docker/tree/v20.13.0) (2022-06-08)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.12.0...v20.13.0)
**Implemented enhancements:**
- update docker linux amd64/arm64 to 20.10.14 [\#365](https://github.com/drone-plugins/drone-docker/pull/365) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- v20.13.0 prep [\#367](https://github.com/drone-plugins/drone-docker/pull/367) ([tphoney](https://github.com/tphoney))
## [v20.12.0](https://github.com/drone-plugins/drone-docker/tree/v20.12.0) (2022-05-16)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.11.0...v20.12.0)
**Implemented enhancements:**
- Add support for multiple Buildkit secrets with env vars or files as source [\#359](https://github.com/drone-plugins/drone-docker/pull/359) ([ste93cry](https://github.com/ste93cry))
- \(DRON-237\) cards add link to image repo, minor cleanup [\#358](https://github.com/drone-plugins/drone-docker/pull/358) ([tphoney](https://github.com/tphoney))
- \(DRON-232\) enable build-kit for secrets consumption [\#356](https://github.com/drone-plugins/drone-docker/pull/356) ([tphoney](https://github.com/tphoney))
**Fixed bugs:**
- \(fix\) Update card.json with UX [\#355](https://github.com/drone-plugins/drone-docker/pull/355) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- prep for v20.12.0 [\#363](https://github.com/drone-plugins/drone-docker/pull/363) ([tphoney](https://github.com/tphoney))
## [v20.11.0](https://github.com/drone-plugins/drone-docker/tree/v20.11.0) (2022-01-19)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.10.9.1...v20.11.0)
**Merged pull requests:**
- new release to fix window semver error [\#354](https://github.com/drone-plugins/drone-docker/pull/354) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(feat\) publish docker data to create drone card [\#347](https://github.com/drone-plugins/drone-docker/pull/347) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v20.10.9.1](https://github.com/drone-plugins/drone-docker/tree/v20.10.9.1) (2022-01-13)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v20.10.9...v20.10.9.1)
**Implemented enhancements:**
- Serialize windows 1809 pipelines [\#348](https://github.com/drone-plugins/drone-docker/pull/348) ([shubham149](https://github.com/shubham149))
- Support for windows images for tags [\#346](https://github.com/drone-plugins/drone-docker/pull/346) ([shubham149](https://github.com/shubham149))
**Fixed bugs:**
- Fix ECR & GCR docker publish on windows [\#352](https://github.com/drone-plugins/drone-docker/pull/352) ([shubham149](https://github.com/shubham149))
- Fix windows docker builds [\#351](https://github.com/drone-plugins/drone-docker/pull/351) ([shubham149](https://github.com/shubham149))
- Fix powershell script to publish windows images [\#350](https://github.com/drone-plugins/drone-docker/pull/350) ([shubham149](https://github.com/shubham149))
**Merged pull requests:**
- release prep for 20.10.9.1 [\#353](https://github.com/drone-plugins/drone-docker/pull/353) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v20.10.9](https://github.com/drone-plugins/drone-docker/tree/v20.10.9) (2021-11-03)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v19.03.9...v20.10.9)
**Merged pull requests:**
- bump to version 20.10.9: [\#342](https://github.com/drone-plugins/drone-docker/pull/342) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Upgrade Docker dind to 20.10.9 for 64bit platforms [\#334](https://github.com/drone-plugins/drone-docker/pull/334) ([gzm0](https://github.com/gzm0))
## [v19.03.9](https://github.com/drone-plugins/drone-docker/tree/v19.03.9) (2021-10-13)
[Full Changelog](https://github.com/drone-plugins/drone-docker/compare/v19.03.8...v19.03.9)
**Implemented enhancements:**
- adding support for externalId [\#333](https://github.com/drone-plugins/drone-docker/pull/333) ([jimsheldon](https://github.com/jimsheldon))
- Add support for automatic opencontainer labels [\#313](https://github.com/drone-plugins/drone-docker/pull/313) ([codrut-fc](https://github.com/codrut-fc))
- add custom seccomp profile [\#312](https://github.com/drone-plugins/drone-docker/pull/312) ([xoxys](https://github.com/xoxys))
- ECR: adding setting to enable image scanning while repo creation [\#300](https://github.com/drone-plugins/drone-docker/pull/300) ([rvoitenko](https://github.com/rvoitenko))
**Fixed bugs:**
- Revert "Update seccomp to 20.10 docker" [\#325](https://github.com/drone-plugins/drone-docker/pull/325) ([bradrydzewski](https://github.com/bradrydzewski))
**Closed issues:**
- Enable auth against multiple registries [\#324](https://github.com/drone-plugins/drone-docker/issues/324)
- Parameter add\_host not work [\#318](https://github.com/drone-plugins/drone-docker/issues/318)
- support customized Dockerfile name ? [\#315](https://github.com/drone-plugins/drone-docker/issues/315)
- Tag wrongly gets parsed as octal [\#311](https://github.com/drone-plugins/drone-docker/issues/311)
- Support TLS 1.3 [\#310](https://github.com/drone-plugins/drone-docker/issues/310)
- Can pugin-docker access workspace content directly? [\#307](https://github.com/drone-plugins/drone-docker/issues/307)
**Merged pull requests:**
- \(maint\) bump git to 1.13 for build and test [\#338](https://github.com/drone-plugins/drone-docker/pull/338) ([tphoney](https://github.com/tphoney))
- \(maint\) v19.03.9 release prep [\#337](https://github.com/drone-plugins/drone-docker/pull/337) ([tphoney](https://github.com/tphoney))
- \(maint\) CI, remove the dry run steps, due to rate limiting [\#323](https://github.com/drone-plugins/drone-docker/pull/323) ([tphoney](https://github.com/tphoney))
- Update seccomp to 20.10 docker [\#322](https://github.com/drone-plugins/drone-docker/pull/322) ([techknowlogick](https://github.com/techknowlogick))
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
-162
View File
@@ -1,162 +0,0 @@
# Cosign Integration for Drone-Docker
This document describes how to use the cosign container image signing feature in drone-docker.
## Overview
The drone-docker plugin now supports automatic container image signing using cosign after each successful push. This provides cryptographic verification that images haven't been tampered with.
## Environment Variables
The plugin accepts three cosign-related environment variables:
### `PLUGIN_COSIGN_PRIVATE_KEY` (Required for signing)
- **Description**: Private key for signing (PEM format content or file path)
- **Format**: Either PEM content or file path to private key
- **Usage**: Should be provided via secrets
### `PLUGIN_COSIGN_PASSWORD` (Optional)
- **Description**: Password for encrypted private keys
- **Usage**: Only needed if your private key is password-protected
### `PLUGIN_COSIGN_PARAMS` (Optional)
- **Description**: Additional cosign parameters
- **Examples**:
- `-a build_id=123` (add annotations)
- `--tlog-upload=false` (disable transparency log)
- `--rekor-url=https://custom-rekor.example.com` (custom rekor instance)
## Usage Examples
### 1. Basic Signing (Drone)
```yaml
kind: pipeline
type: docker
name: default
steps:
- name: docker
image: plugins/docker
settings:
repo: myregistry/myapp
tags: latest
cosign_private_key:
from_secret: cosign_private_key
cosign_password:
from_secret: cosign_password
```
### 2. Advanced Signing with Annotations (Drone)
```yaml
steps:
- name: docker
image: plugins/docker
settings:
repo: myregistry/myapp
tags:
- latest
- ${DRONE_BUILD_NUMBER}
cosign_private_key:
from_secret: cosign_private_key
cosign_params: "-a build_id=${DRONE_BUILD_NUMBER} -a commit_sha=${DRONE_COMMIT_SHA} -a branch=${DRONE_BRANCH}"
```
### 3. Harness CI/CD Usage
```yaml
- step:
type: Plugin
name: Build and Sign
identifier: build_and_sign
spec:
connectorRef: account.harnessImage
image: plugins/docker
settings:
repo: myregistry/myapp
tags: <+pipeline.sequenceId>
cosign_private_key: <+secrets.getValue("cosign_private_key")>
cosign_password: <+secrets.getValue("cosign_password")>
cosign_params: "-a harness_build=<+pipeline.sequenceId> -a harness_project=<+project.name>"
```
## Key Management
### Generating Cosign Keys
```bash
# Generate a new key pair
cosign generate-key-pair
# This creates:
# - cosign.key (private key)
# - cosign.pub (public key)
```
### Storing Keys Securely
**Harness Secrets:**
1. Go to Project Settings → Secrets
2. Create new secret with type "File" for private key
3. Create new secret with type "Text" for password
## Security Features
### Automatic Validation
-**Private key format validation**: Ensures PEM format is correct
-**Password requirement detection**: Warns if encrypted key needs password
-**Keyless signing prevention**: Warns that OIDC keyless signing isn't supported
### Error Handling
- **Invalid private key**: `❌ Invalid private key format. Expected PEM format`
- **Missing password**: `🔐 Encrypted private key requires password. Set PLUGIN_COSIGN_PASSWORD`
- **Keyless signing**: `⚠️ WARNING: Keyless signing (OIDC) isn't supported yet in this plugin`
## Signing Behavior
### When Signing Occurs
-**After each successful push**: Images are signed immediately after push
-**Multiple tags**: Each tag gets signed individually
-**Push-only mode**: Works with existing images
-**Dry-run respect**: Skips signing in dry-run mode
### Image References
- **Preferred**: Signs by digest (e.g., `image@sha256:abc123...`) for security
- **Fallback**: Signs by tag if digest unavailable
### Authentication
- **Registry auth**: Automatically uses existing Docker registry credentials
## Verification
To verify a signed image:
```bash
# Verify with public key
cosign verify --key cosign.pub myregistry/myapp:latest
# Verify with annotations
cosign verify --key cosign.pub \
-a build_id=123 \
myregistry/myapp:latest
```
## Troubleshooting
### Common Issues
1. **"cosign: command not found"**
- The container image includes cosign binary
- Use the latest plugin image: `plugins/docker:latest`
2. **"keyless signing not supported"**
- This plugin only supports private key signing
- Don't use `--oidc` or `--identity-token` in `cosign_params`
3. **"encrypted private key requires password"**
- Set `PLUGIN_COSIGN_PASSWORD` environment variable
- Or use an unencrypted private key
4. **Registry authentication issues**
- Cosign uses the same Docker registry credentials
- Ensure Docker login is working first
-118
View File
@@ -10,14 +10,6 @@
Drone plugin uses Docker-in-Docker to build and publish Docker images to a container registry. For the usage information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/drone-plugins/drone-docker/). Drone plugin uses Docker-in-Docker to build and publish Docker images to a container registry. For the usage information and a listing of the available options please take a look at [the docs](http://plugins.drone.io/drone-plugins/drone-docker/).
### Git Leaks
Run the following script to install git-leaks support to this repo.
```
chmod +x ./git-hooks/install.sh
./git-hooks/install.sh
```
## Build ## Build
Build the binaries with the following commands: Build the binaries with the following commands:
@@ -33,7 +25,6 @@ go build -v -a -tags netgo -o release/linux/amd64/drone-gcr ./cmd/drone-gcr
go build -v -a -tags netgo -o release/linux/amd64/drone-ecr ./cmd/drone-ecr go build -v -a -tags netgo -o release/linux/amd64/drone-ecr ./cmd/drone-ecr
go build -v -a -tags netgo -o release/linux/amd64/drone-acr ./cmd/drone-acr go build -v -a -tags netgo -o release/linux/amd64/drone-acr ./cmd/drone-acr
go build -v -a -tags netgo -o release/linux/amd64/drone-heroku ./cmd/drone-heroku go build -v -a -tags netgo -o release/linux/amd64/drone-heroku ./cmd/drone-heroku
go build -v -a -tags netgo -o release/linux/amd64/drone-gar ./cmd/drone-gar
``` ```
## Docker ## Docker
@@ -65,57 +56,12 @@ docker build \
--label org.label-schema.build-date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ --label org.label-schema.build-date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--label org.label-schema.vcs-ref=$(git rev-parse --short HEAD) \ --label org.label-schema.vcs-ref=$(git rev-parse --short HEAD) \
--file docker/heroku/Dockerfile.linux.amd64 --tag plugins/heroku . --file docker/heroku/Dockerfile.linux.amd64 --tag plugins/heroku .
docker build \
--label org.label-schema.build-date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--label org.label-schema.vcs-ref=$(git rev-parse --short HEAD) \
--file docker/gar/Dockerfile.linux.amd64 --tag plugins/gar .
``` ```
## Usage ## Usage
> Notice: Be aware that the Docker plugin currently requires privileged capabilities, otherwise the integrated Docker daemon is not able to start. > Notice: Be aware that the Docker plugin currently requires privileged capabilities, otherwise the integrated Docker daemon is not able to start.
### Using Docker buildkit Secrets
```yaml
kind: pipeline
name: default
steps:
- name: build dummy docker file and publish
image: plugins/docker
pull: never
settings:
repo: tphoney/test
tags: latest
secret: id=mysecret,src=secret-file
username:
from_secret: docker_username
password:
from_secret: docker_password
```
Using a dockerfile that references the secret-file
```bash
# syntax=docker/dockerfile:1.2
FROM alpine
# shows secret from default secret location:
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
```
and a secret file called secret-file
```
COOL BANANAS
```
### Running from the CLI
```console ```console
docker run --rm \ docker run --rm \
-e PLUGIN_TAG=latest \ -e PLUGIN_TAG=latest \
@@ -126,67 +72,3 @@ docker run --rm \
--privileged \ --privileged \
plugins/docker --dry-run plugins/docker --dry-run
``` ```
### GAR (Google Artifact Registry)
```yaml
kind: pipeline
name: default
type: docker
steps:
- name: push-to-gar
image: plugins/gar
pull: never
settings:
tag: latest
repo: project-id/repo/image-name
location: us
json_key:
from_secret: gcr_json_key
```
### GAR (Google Artifact Registry) using workload identity (OIDC)
```yaml
steps:
- name: push-to-gar
image: plugins/gar
pull: never
settings:
tag: latest
repo: project-id/repo/image-name
location: europe
project_number: project-number
pool_id: workload identity pool id
provider_id: workload identity provider id
service_account_email: service account email
oidc_token_id:
from_secret: token
```
## Developer Notes
- When updating the base image, you will need to update for each architecture and OS.
- Arm32 base images are no longer being updated.
## Release procedure
Run the changelog generator.
```BASH
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u drone-plugins -p drone-docker -t <secret github token>
```
You can generate a token by logging into your GitHub account and going to Settings -> Personal access tokens.
Next we tag the PR's with the fixes or enhancements labels. If the PR does not fufil the requirements, do not add a label.
Run the changelog generator again with the future version according to semver.
```BASH
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator -u drone-plugins -p drone-docker -t <secret token> --future-release v1.0.0
```
Create your pull request for the release. Get it merged then tag the release.
-88
View File
@@ -1,88 +0,0 @@
package docker
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"strings"
"time"
"github.com/drone/drone-go/drone"
"github.com/inhies/go-bytesize"
)
func (p Plugin) writeCard() error {
cmd := exec.Command(dockerExe, "inspect", p.Build.TempTag)
data, err := cmd.CombinedOutput()
if err != nil {
return err
}
out := Card{}
if err := json.Unmarshal(data, &out); err != nil {
return err
}
inspect := out[0]
inspect.SizeString = fmt.Sprint(bytesize.New(float64(inspect.Size)))
inspect.VirtualSizeString = fmt.Sprint(bytesize.New(float64(inspect.VirtualSize)))
inspect.Time = fmt.Sprint(inspect.Metadata.LastTagTime.Format(time.RFC3339))
// change slice of tags to slice of TagStruct
var sliceTagStruct []TagStruct
for _, tag := range inspect.RepoTags {
sliceTagStruct = append(sliceTagStruct, TagStruct{Tag: tag})
}
inspect.ParsedRepoTags = sliceTagStruct[1:] // remove the first tag which is always "hash:latest"
// create the url from repo and registry
inspect.URL = mapRegistryToURL(p.Daemon.Registry, p.Build.Repo)
cardData, _ := json.Marshal(inspect)
card := drone.CardInput{
Schema: "https://drone-plugins.github.io/drone-docker/card.json",
Data: cardData,
}
writeCard(p.CardPath, &card)
return nil
}
func writeCard(path string, card interface{}) {
data, _ := json.Marshal(card)
switch {
case path == "/dev/stdout":
writeCardTo(os.Stdout, data)
case path == "/dev/stderr":
writeCardTo(os.Stderr, data)
case path != "":
ioutil.WriteFile(path, data, 0644)
}
}
func writeCardTo(out io.Writer, data []byte) {
encoded := base64.StdEncoding.EncodeToString(data)
io.WriteString(out, "\u001B]1338;")
io.WriteString(out, encoded)
io.WriteString(out, "\u001B]0m")
io.WriteString(out, "\n")
}
func mapRegistryToURL(registry, repo string) (url string) {
url = "https://"
var domain string
if strings.Contains(registry, "amazonaws.com") {
domain = "gallery.ecr.aws/"
} else if strings.Contains(registry, "gcr.io") {
domain = "console.cloud.google.com/gcr/images"
} else {
// default to docker hub
domain = "hub.docker.com/r/"
}
url = path.Join(url, domain, repo)
return url
}
+2 -241
View File
@@ -1,50 +1,12 @@
package main package main
import ( import (
"context"
"encoding/base64"
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http"
"net/url"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"strings" "strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
docker "github.com/drone-plugins/drone-docker"
azureutil "github.com/drone-plugins/drone-docker/internal/azure"
)
type subscriptionUrlResponse struct {
Value []struct {
ID string `json:"id"`
} `json:"value"`
}
const (
acrCertFile = "acr-cert.pem"
azSubscriptionApiVersion = "2021-04-01"
azSubscriptionBaseUrl = "https://management.azure.com/subscriptions/"
basePublicUrl = "https://portal.azure.com/#view/Microsoft_Azure_ContainerRegistries/TagMetadataBlade/registryId/"
defaultUsername = "00000000-0000-0000-0000-000000000000"
// Environment variable names for Azure Environment Credential
clientIdEnv = "AZURE_CLIENT_ID"
clientSecretKeyEnv = "AZURE_CLIENT_SECRET"
tenantKeyEnv = "AZURE_TENANT_ID"
certPathEnv = "AZURE_CLIENT_CERTIFICATE_PATH"
)
var (
acrCertPath = filepath.Join(os.TempDir(), acrCertFile)
) )
func main() { func main() {
@@ -56,21 +18,8 @@ func main() {
var ( var (
repo = getenv("PLUGIN_REPO") repo = getenv("PLUGIN_REPO")
registry = getenv("PLUGIN_REGISTRY") registry = getenv("PLUGIN_REGISTRY")
// If these credentials are provided, they will be directly used
// for docker login
username = getenv("SERVICE_PRINCIPAL_CLIENT_ID") username = getenv("SERVICE_PRINCIPAL_CLIENT_ID")
password = getenv("SERVICE_PRINCIPAL_CLIENT_SECRET") password = getenv("SERVICE_PRINCIPAL_CLIENT_SECRET")
// Service principal credentials
clientId = getenv("CLIENT_ID", "AZURE_CLIENT_ID", "AZURE_APP_ID", "PLUGIN_CLIENT_ID")
clientSecret = getenv("CLIENT_SECRET", "PLUGIN_CLIENT_SECRET")
clientCert = getenv("CLIENT_CERTIFICATE", "PLUGIN_CLIENT_CERTIFICATE")
tenantId = getenv("TENANT_ID", "AZURE_TENANT_ID", "PLUGIN_TENANT_ID")
subscriptionId = getenv("SUBSCRIPTION_ID", "PLUGIN_SUBSCRIPTION_ID")
publicUrl = getenv("DAEMON_REGISTRY", "PLUGIN_DAEMON_REGISTRY")
authorityHost = getenv("AZURE_AUTHORITY_HOST", "PLUGIN_AZURE_AUTHORITY_HOST")
idToken = getenv("PLUGIN_OIDC_TOKEN_ID")
) )
// default registry value // default registry value
@@ -78,37 +27,6 @@ func main() {
registry = "azurecr.io" registry = "azurecr.io"
} }
// Get auth if username and password is not specified
if username == "" && password == "" {
// docker login credentials are not provided
var err error
username = defaultUsername
if idToken != "" && clientId != "" && tenantId != "" {
logrus.Debug("Using OIDC authentication flow")
var aadToken string
aadToken, err = azureutil.GetAADAccessTokenViaClientAssertion(context.Background(), tenantId, clientId, idToken, authorityHost)
if err != nil {
logrus.Fatal(err)
}
var p string
p, err = getPublicUrl(aadToken, registry, subscriptionId)
if err == nil {
publicUrl = p
} else {
fmt.Fprintf(os.Stderr, "failed to get public url with error: %s\n", err)
}
password, err = fetchACRToken(tenantId, aadToken, registry)
if err != nil {
logrus.Fatal(err)
}
} else {
password, publicUrl, err = getAuth(clientId, clientSecret, clientCert, tenantId, subscriptionId, registry)
if err != nil {
logrus.Fatal(err)
}
}
}
// must use the fully qualified repo name. If the // must use the fully qualified repo name. If the
// repo name does not have the registry prefix we // repo name does not have the registry prefix we
// should prepend. // should prepend.
@@ -120,174 +38,17 @@ func main() {
os.Setenv("PLUGIN_REGISTRY", registry) os.Setenv("PLUGIN_REGISTRY", registry)
os.Setenv("DOCKER_USERNAME", username) os.Setenv("DOCKER_USERNAME", username)
os.Setenv("DOCKER_PASSWORD", password) os.Setenv("DOCKER_PASSWORD", password)
os.Setenv("PLUGIN_REGISTRY_TYPE", "ACR")
if publicUrl != "" {
// Set this env variable if public URL for artifact is available
// If not, we will fall back to registry url
os.Setenv("ARTIFACT_REGISTRY", publicUrl)
}
// invoke the base docker plugin binary // invoke the base docker plugin binary
cmd := exec.Command(docker.GetDroneDockerExecCmd()) cmd := exec.Command("drone-docker")
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
logrus.Fatal(err) os.Exit(1)
} }
} }
func getAuth(clientId, clientSecret, clientCert, tenantId, subscriptionId, registry string) (string, string, error) {
// Verify inputs
if tenantId == "" {
return "", "", fmt.Errorf("tenantId cannot be empty for AAD authentication")
}
if clientId == "" {
return "", "", fmt.Errorf("clientId cannot be empty for AAD authentication")
}
if clientSecret == "" && clientCert == "" {
return "", "", fmt.Errorf("one of client secret or client cert should be defined")
}
// Setup cert
if clientCert != "" {
err := setupACRCert(clientCert, acrCertPath)
if err != nil {
errors.Wrap(err, "failed to push setup cert file")
}
}
// Get AZ env
if err := os.Setenv(clientIdEnv, clientId); err != nil {
return "", "", errors.Wrap(err, "failed to set env variable client Id")
}
if err := os.Setenv(clientSecretKeyEnv, clientSecret); err != nil {
return "", "", errors.Wrap(err, "failed to set env variable client secret")
}
if err := os.Setenv(tenantKeyEnv, tenantId); err != nil {
return "", "", errors.Wrap(err, "failed to set env variable tenant Id")
}
if err := os.Setenv(certPathEnv, acrCertPath); err != nil {
return "", "", errors.Wrap(err, "failed to set env variable cert path")
}
env, err := azidentity.NewEnvironmentCredential(nil)
if err != nil {
return "", "", errors.Wrap(err, "failed to get env credentials from azure")
}
os.Unsetenv(clientIdEnv)
os.Unsetenv(clientSecretKeyEnv)
os.Unsetenv(tenantKeyEnv)
os.Unsetenv(certPathEnv)
// Fetch AAD token
policy := policy.TokenRequestOptions{
Scopes: []string{"https://management.azure.com/.default"},
}
aadToken, err := env.GetToken(context.Background(), policy)
if err != nil {
return "", "", errors.Wrap(err, "failed to fetch access token")
}
// Get public URL for artifacts
publicUrl, err := getPublicUrl(aadToken.Token, registry, subscriptionId)
if err != nil {
// execution should not fail because of this error
fmt.Fprintf(os.Stderr, "failed to get public url with error: %s\n", err)
}
// Fetch token
ACRToken, err := fetchACRToken(tenantId, aadToken.Token, registry)
if err != nil {
return "", "", errors.Wrap(err, "failed to fetch ACR token")
}
return ACRToken, publicUrl, nil
}
func fetchACRToken(tenantId, token, registry string) (string, error) {
// oauth exchange
formData := url.Values{
"grant_type": {"access_token"},
"service": {registry},
"tenant": {tenantId},
"access_token": {token},
}
jsonResponse, err := http.PostForm(fmt.Sprintf("https://%s/oauth2/exchange", registry), formData)
if err != nil || jsonResponse == nil {
return "", errors.Wrap(err, "failed to fetch ACR token")
}
// fetch token from response
var response map[string]interface{}
err = json.NewDecoder(jsonResponse.Body).Decode(&response)
if err != nil {
return "", errors.Wrap(err, "failed to decode oauth exchange response")
}
// Parse the refresh_token from the response
if t, found := response["refresh_token"]; found {
if refreshToken, ok := t.(string); ok {
return refreshToken, nil
}
return "", errors.New("failed to cast refresh token from acr")
}
return "", errors.Wrap(err, "refresh token not found in response of oauth exchange call")
}
func setupACRCert(cert, certPath string) error {
decoded, err := base64.StdEncoding.DecodeString(cert)
if err != nil {
return errors.Wrap(err, "failed to base64 decode ACR certificate")
}
err = ioutil.WriteFile(certPath, decoded, 0644)
if err != nil {
return errors.Wrap(err, "failed to write ACR certificate")
}
return nil
}
func getPublicUrl(token, registryUrl, subscriptionId string) (string, error) {
if len(subscriptionId) == 0 || registryUrl == "" {
return "", nil
}
registry := strings.Split(registryUrl, ".")[0]
filter := fmt.Sprintf("resourceType eq 'Microsoft.ContainerRegistry/registries' and name eq '%s'", registry)
params := url.Values{}
params.Add("$filter", filter)
params.Add("api-version", azSubscriptionApiVersion)
params.Add("$select", "id")
url := azSubscriptionBaseUrl + subscriptionId + "/resources?" + params.Encode()
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println(err)
return "", errors.Wrap(err, "failed to create request for getting container registry setting")
}
req.Header.Add("Authorization", "Bearer "+token)
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return "", errors.Wrap(err, "failed to send request for getting container registry setting")
}
defer res.Body.Close()
var response subscriptionUrlResponse
err = json.NewDecoder(res.Body).Decode(&response)
if err != nil {
return "", errors.Wrap(err, "failed to send request for getting container registry setting")
}
if len(response.Value) == 0 {
return "", errors.New("no id present for base url")
}
return basePublicUrl + encodeParam(response.Value[0].ID), nil
}
func encodeParam(s string) string {
return url.QueryEscape(s)
}
func getenv(key ...string) (s string) { func getenv(key ...string) (s string) {
for _, k := range key { for _, k := range key {
s = os.Getenv(k) s = os.Getenv(k)
-32
View File
@@ -1,32 +0,0 @@
package main
import (
"os"
"testing"
)
func TestGetAuthInputValidation(t *testing.T) {
// missing tenant
if _, _, err := getAuth("client", "secret", "", "", "sub", "registry.azurecr.io"); err == nil {
t.Fatalf("expected error for missing tenantId")
}
// missing clientId
if _, _, err := getAuth("", "secret", "", "tenant", "sub", "registry.azurecr.io"); err == nil {
t.Fatalf("expected error for missing clientId")
}
// missing both secret and cert
if _, _, err := getAuth("client", "", "", "tenant", "sub", "registry.azurecr.io"); err == nil {
t.Fatalf("expected error for missing credentials")
}
}
func TestGetenvAuthorityHost(t *testing.T) {
os.Setenv("AZURE_AUTHORITY_HOST", "https://login.microsoftonline.us")
defer os.Unsetenv("AZURE_AUTHORITY_HOST")
got := getenv("AZURE_AUTHORITY_HOST")
if got != "https://login.microsoftonline.us" {
t.Fatalf("expected AZURE_AUTHORITY_HOST to be returned, got %q", got)
}
}
-33
View File
@@ -1,33 +0,0 @@
package main
import (
"strings"
)
// CustomStringSliceFlag is like a regular StringSlice flag but with
// semicolon as a delimiter
type CustomStringSliceFlag struct {
Value []string
}
func (f *CustomStringSliceFlag) GetValue() []string {
if f.Value == nil {
return make([]string, 0)
}
return f.Value
}
func (f *CustomStringSliceFlag) String() string {
if f.Value == nil {
return ""
}
return strings.Join(f.Value, ";")
}
func (f *CustomStringSliceFlag) Set(v string) error {
for _, s := range strings.Split(v, ";") {
s = strings.TrimSpace(s)
f.Value = append(f.Value, s)
}
return nil
}
+25 -165
View File
@@ -2,16 +2,12 @@ package main
import ( import (
"os" "os"
"runtime"
"strings"
"github.com/dchest/uniuri"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
docker "github.com/drone-plugins/drone-docker" docker "github.com/drone-plugins/drone-docker"
"github.com/drone-plugins/drone-plugin-lib/drone"
) )
var ( var (
@@ -54,7 +50,7 @@ func main() {
cli.StringFlag{ cli.StringFlag{
Name: "daemon.mirror", Name: "daemon.mirror",
Usage: "docker daemon registry mirror", Usage: "docker daemon registry mirror",
EnvVar: "PLUGIN_MIRROR,DOCKER_PLUGIN_MIRROR", EnvVar: "PLUGIN_MIRROR",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "daemon.storage-driver", Name: "daemon.storage-driver",
@@ -151,17 +147,6 @@ func main() {
Usage: "build args", Usage: "build args",
EnvVar: "PLUGIN_BUILD_ARGS_FROM_ENV", EnvVar: "PLUGIN_BUILD_ARGS_FROM_ENV",
}, },
cli.GenericFlag{
Name: "args-new",
Usage: "build args new",
EnvVar: "PLUGIN_BUILD_ARGS_NEW",
Value: new(CustomStringSliceFlag),
},
cli.BoolFlag{
Name: "plugin-multiple-build-agrs",
Usage: "plugin multiple build agrs",
EnvVar: "PLUGIN_MULTIPLE_BUILD_ARGS",
},
cli.BoolFlag{ cli.BoolFlag{
Name: "quiet", Name: "quiet",
Usage: "quiet docker build", Usage: "quiet docker build",
@@ -207,16 +192,6 @@ func main() {
Usage: "label-schema labels", Usage: "label-schema labels",
EnvVar: "PLUGIN_LABEL_SCHEMA", EnvVar: "PLUGIN_LABEL_SCHEMA",
}, },
cli.BoolTFlag{
Name: "auto-label",
Usage: "auto-label true|false",
EnvVar: "PLUGIN_AUTO_LABEL",
},
cli.StringFlag{
Name: "link",
Usage: "link https://example.com/org/repo-name",
EnvVar: "PLUGIN_REPO_LINK,DRONE_REPO_LINK",
},
cli.StringFlag{ cli.StringFlag{
Name: "docker.registry", Name: "docker.registry",
Usage: "docker registry", Usage: "docker registry",
@@ -233,21 +208,6 @@ func main() {
Usage: "docker password", Usage: "docker password",
EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD", EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD",
}, },
cli.StringFlag{
Name: "docker.baseimageusername",
Usage: "Docker username for base image registry",
EnvVar: "PLUGIN_DOCKER_USERNAME,PLUGIN_BASE_IMAGE_USERNAME,DOCKER_BASE_IMAGE_USERNAME",
},
cli.StringFlag{
Name: "docker.baseimagepassword",
Usage: "Docker password for base image registry",
EnvVar: "PLUGIN_DOCKER_PASSWORD,PLUGIN_BASE_IMAGE_PASSWORD,DOCKER_BASE_IMAGE_PASSWORD",
},
cli.StringFlag{
Name: "docker.baseimageregistry",
Usage: "Docker registry for base image registry",
EnvVar: "PLUGIN_DOCKER_REGISTRY,PLUGIN_BASE_IMAGE_REGISTRY,DOCKER_BASE_IMAGE_REGISTRY",
},
cli.StringFlag{ cli.StringFlag{
Name: "docker.email", Name: "docker.email",
Usage: "docker email", Usage: "docker email",
@@ -256,7 +216,7 @@ func main() {
cli.StringFlag{ cli.StringFlag{
Name: "docker.config", Name: "docker.config",
Usage: "docker json dockerconfig content", Usage: "docker json dockerconfig content",
EnvVar: "PLUGIN_CONFIG,DOCKER_PLUGIN_CONFIG", EnvVar: "PLUGIN_CONFIG",
}, },
cli.BoolTFlag{ cli.BoolTFlag{
Name: "docker.purge", Name: "docker.purge",
@@ -278,67 +238,6 @@ func main() {
Usage: "additional host:IP mapping", Usage: "additional host:IP mapping",
EnvVar: "PLUGIN_ADD_HOST", EnvVar: "PLUGIN_ADD_HOST",
}, },
cli.StringFlag{
Name: "secret",
Usage: "secret key value pair eg id=MYSECRET",
EnvVar: "PLUGIN_SECRET",
},
cli.StringSliceFlag{
Name: "secrets-from-env",
Usage: "secret key value pair eg secret_name=secret",
EnvVar: "PLUGIN_SECRETS_FROM_ENV",
},
cli.StringSliceFlag{
Name: "secrets-from-file",
Usage: "secret key value pairs eg secret_name=/path/to/secret",
EnvVar: "PLUGIN_SECRETS_FROM_FILE",
},
cli.StringFlag{
Name: "drone-card-path",
Usage: "card path location to write to",
EnvVar: "DRONE_CARD_PATH",
},
cli.StringFlag{
Name: "platform",
Usage: "platform value to pass to docker",
EnvVar: "PLUGIN_PLATFORM",
},
cli.StringFlag{
Name: "ssh-agent-key",
Usage: "ssh agent key to use",
EnvVar: "PLUGIN_SSH_AGENT_KEY",
},
cli.StringFlag{
Name: "artifact-file",
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
EnvVar: "PLUGIN_ARTIFACT_FILE",
},
cli.StringFlag{
Name: "registry-type",
Usage: "registry type",
EnvVar: "PLUGIN_REGISTRY_TYPE",
},
cli.StringFlag{
Name: "access-token",
Usage: "access token",
EnvVar: "ACCESS_TOKEN",
},
// Cosign signing configuration
cli.StringFlag{
Name: "cosign.private-key",
Usage: "cosign private key content or file path for signing",
EnvVar: "PLUGIN_COSIGN_PRIVATE_KEY",
},
cli.StringFlag{
Name: "cosign.password",
Usage: "password for encrypted cosign private key",
EnvVar: "PLUGIN_COSIGN_PASSWORD",
},
cli.StringFlag{
Name: "cosign.params",
Usage: "additional cosign parameters (e.g., annotations, flags)",
EnvVar: "PLUGIN_COSIGN_PARAMS",
},
} }
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
@@ -347,53 +246,35 @@ func main() {
} }
func run(c *cli.Context) error { func run(c *cli.Context) error {
registryType := drone.Docker
if c.String("registry-type") != "" {
registryType = drone.RegistryType(c.String("registry-type"))
}
plugin := docker.Plugin{ plugin := docker.Plugin{
Dryrun: c.Bool("dry-run"), Dryrun: c.Bool("dry-run"),
Cleanup: c.BoolT("docker.purge"), Cleanup: c.BoolT("docker.purge"),
Login: docker.Login{ Login: docker.Login{
Registry: c.String("docker.registry"), Registry: c.String("docker.registry"),
Username: c.String("docker.username"), Username: c.String("docker.username"),
Password: c.String("docker.password"), Password: c.String("docker.password"),
Email: c.String("docker.email"), Email: c.String("docker.email"),
Config: c.String("docker.config"), Config: c.String("docker.config"),
AccessToken: c.String("access-token"),
}, },
CardPath: c.String("drone-card-path"),
ArtifactFile: c.String("artifact-file"),
Build: docker.Build{ Build: docker.Build{
Remote: c.String("remote.url"), Remote: c.String("remote.url"),
Name: c.String("commit.sha"), Name: c.String("commit.sha"),
TempTag: generateTempTag(), Dockerfile: c.String("dockerfile"),
Dockerfile: c.String("dockerfile"), Context: c.String("context"),
Context: c.String("context"), Tags: c.StringSlice("tags"),
Tags: c.StringSlice("tags"), Args: c.StringSlice("args"),
Args: c.StringSlice("args"), ArgsEnv: c.StringSlice("args-from-env"),
ArgsEnv: c.StringSlice("args-from-env"), Target: c.String("target"),
ArgsNew: c.Generic("args-new").(*CustomStringSliceFlag).GetValue(), Squash: c.Bool("squash"),
IsMultipleBuildArgs: c.Bool("plugin-multiple-build-agrs"), Pull: c.BoolT("pull-image"),
Target: c.String("target"), CacheFrom: c.StringSlice("cache-from"),
Squash: c.Bool("squash"), Compress: c.Bool("compress"),
Pull: c.BoolT("pull-image"), Repo: c.String("repo"),
CacheFrom: c.StringSlice("cache-from"), Labels: c.StringSlice("custom-labels"),
Compress: c.Bool("compress"), LabelSchema: c.StringSlice("label-schema"),
Repo: c.String("repo"), NoCache: c.Bool("no-cache"),
Labels: c.StringSlice("custom-labels"), AddHost: c.StringSlice("add-host"),
LabelSchema: c.StringSlice("label-schema"), Quiet: c.Bool("quiet"),
AutoLabel: c.BoolT("auto-label"),
Link: c.String("link"),
NoCache: c.Bool("no-cache"),
Secret: c.String("secret"),
SecretEnvs: c.StringSlice("secrets-from-env"),
SecretFiles: c.StringSlice("secrets-from-file"),
AddHost: c.StringSlice("add-host"),
Quiet: c.Bool("quiet"),
Platform: c.String("platform"),
SSHAgentKey: c.String("ssh-agent-key"),
}, },
Daemon: docker.Daemon{ Daemon: docker.Daemon{
Registry: c.String("docker.registry"), Registry: c.String("docker.registry"),
@@ -409,15 +290,6 @@ func run(c *cli.Context) error {
DNSSearch: c.StringSlice("daemon.dns-search"), DNSSearch: c.StringSlice("daemon.dns-search"),
MTU: c.String("daemon.mtu"), MTU: c.String("daemon.mtu"),
Experimental: c.Bool("daemon.experimental"), Experimental: c.Bool("daemon.experimental"),
RegistryType: registryType,
},
BaseImageRegistry: c.String("docker.baseimageregistry"),
BaseImageUsername: c.String("docker.baseimageusername"),
BaseImagePassword: c.String("docker.baseimagepassword"),
Cosign: docker.CosignConfig{
PrivateKey: c.String("cosign.private-key"),
Password: c.String("cosign.password"),
Params: c.String("cosign.params"),
}, },
} }
@@ -443,15 +315,3 @@ func run(c *cli.Context) error {
return plugin.Exec() return plugin.Exec()
} }
func generateTempTag() string {
return strings.ToLower(uniuri.New())
}
func GetExecCmd() string {
if runtime.GOOS == "windows" {
return "C:/bin/drone-docker.exe"
}
return "drone-docker"
}
+19 -117
View File
@@ -11,21 +11,14 @@ import (
"strings" "strings"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecr" "github.com/aws/aws-sdk-go/service/ecr"
docker "github.com/drone-plugins/drone-docker"
) )
type ecrAPI interface {
DescribeImages(*ecr.DescribeImagesInput) (*ecr.DescribeImagesOutput, error)
}
const defaultRegion = "us-east-1" const defaultRegion = "us-east-1"
func main() { func main() {
@@ -35,19 +28,15 @@ func main() {
} }
var ( var (
repo = getenv("PLUGIN_REPO") repo = getenv("PLUGIN_REPO")
registry = getenv("PLUGIN_REGISTRY") registry = getenv("PLUGIN_REGISTRY")
region = getenv("PLUGIN_REGION", "ECR_REGION", "AWS_REGION") region = getenv("PLUGIN_REGION", "ECR_REGION", "AWS_REGION")
key = getenv("PLUGIN_ACCESS_KEY", "ECR_ACCESS_KEY", "AWS_ACCESS_KEY_ID") key = getenv("PLUGIN_ACCESS_KEY", "ECR_ACCESS_KEY", "AWS_ACCESS_KEY_ID")
secret = getenv("PLUGIN_SECRET_KEY", "ECR_SECRET_KEY", "AWS_SECRET_ACCESS_KEY") secret = getenv("PLUGIN_SECRET_KEY", "ECR_SECRET_KEY", "AWS_SECRET_ACCESS_KEY")
create = parseBoolOrDefault(false, getenv("PLUGIN_CREATE_REPOSITORY", "ECR_CREATE_REPOSITORY")) create = parseBoolOrDefault(false, getenv("PLUGIN_CREATE_REPOSITORY", "ECR_CREATE_REPOSITORY"))
lifecyclePolicy = getenv("PLUGIN_LIFECYCLE_POLICY") lifecyclePolicy = getenv("PLUGIN_LIFECYCLE_POLICY")
repositoryPolicy = getenv("PLUGIN_REPOSITORY_POLICY") repositoryPolicy = getenv("PLUGIN_REPOSITORY_POLICY")
assumeRole = getenv("PLUGIN_ASSUME_ROLE") assumeRole = getenv("PLUGIN_ASSUME_ROLE")
externalId = getenv("PLUGIN_EXTERNAL_ID")
scanOnPush = parseBoolOrDefault(false, getenv("PLUGIN_SCAN_ON_PUSH"))
idToken = os.Getenv("PLUGIN_OIDC_TOKEN_ID")
skipPushIfTagExists = parseBoolOrDefault(false, getenv("PLUGIN_SKIP_PUSH_IF_TAG_EXISTS"))
) )
// set the region // set the region
@@ -67,7 +56,7 @@ func main() {
log.Fatal(fmt.Sprintf("error creating aws session: %v", err)) log.Fatal(fmt.Sprintf("error creating aws session: %v", err))
} }
svc := getECRClient(sess, assumeRole, externalId, idToken) svc := getECRClient(sess, assumeRole)
username, password, defaultRegistry, err := getAuthInfo(svc) username, password, defaultRegistry, err := getAuthInfo(svc)
if registry == "" { if registry == "" {
@@ -83,14 +72,10 @@ func main() {
} }
if create { if create {
err = ensureRepoExists(svc, trimHostname(repo, registry), scanOnPush) err = ensureRepoExists(svc, trimHostname(repo, registry))
if err != nil { if err != nil {
log.Fatal(fmt.Sprintf("error creating ECR repo: %v", err)) log.Fatal(fmt.Sprintf("error creating ECR repo: %v", err))
} }
err = updateImageScannningConfig(svc, trimHostname(repo, registry), scanOnPush)
if err != nil {
log.Fatal(fmt.Sprintf("error updating scan on push for ECR repo: %v", err))
}
} }
if lifecyclePolicy != "" { if lifecyclePolicy != "" {
@@ -117,42 +102,13 @@ func main() {
os.Setenv("PLUGIN_REGISTRY", registry) os.Setenv("PLUGIN_REGISTRY", registry)
os.Setenv("DOCKER_USERNAME", username) os.Setenv("DOCKER_USERNAME", username)
os.Setenv("DOCKER_PASSWORD", password) os.Setenv("DOCKER_PASSWORD", password)
os.Setenv("PLUGIN_REGISTRY_TYPE", "ECR")
// Skip if tag already exits for both mutable and immutable repos
if skipPushIfTagExists {
tagInput := getenv("PLUGIN_TAG", "PLUGIN_TAGS")
var tags []string
if tagInput == "" {
tags = []string{"latest"}
} else {
for _, t := range strings.Split(tagInput, ",") {
trimmed := strings.TrimSpace(t)
if trimmed != "" {
tags = append(tags, trimmed)
}
}
}
repositoryName := trimHostname(repo, registry)
for _, t := range tags {
exists, err := tagExists(svc, repositoryName, t)
if err != nil {
logrus.Fatalf("Error checking if image exists for tag %s: %v", t, err)
}
if exists {
logrus.Infof("%s:%s: Image tag exists. Skipping push.", repo, t)
os.Exit(0)
}
}
}
// invoke the base docker plugin binary // invoke the base docker plugin binary
cmd := exec.Command(docker.GetDroneDockerExecCmd()) cmd := exec.Command("drone-docker")
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
if err = cmd.Run(); err != nil { if err = cmd.Run(); err != nil {
logrus.Fatal(err) os.Exit(1)
} }
} }
@@ -162,10 +118,9 @@ func trimHostname(repo, registry string) string {
return repo return repo
} }
func ensureRepoExists(svc *ecr.ECR, name string, scanOnPush bool) (err error) { func ensureRepoExists(svc *ecr.ECR, name string) (err error) {
input := &ecr.CreateRepositoryInput{} input := &ecr.CreateRepositoryInput{}
input.SetRepositoryName(name) input.SetRepositoryName(name)
input.SetImageScanningConfiguration(&ecr.ImageScanningConfiguration{ScanOnPush: &scanOnPush})
_, err = svc.CreateRepository(input) _, err = svc.CreateRepository(input)
if err != nil { if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ecr.ErrCodeRepositoryAlreadyExistsException { if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ecr.ErrCodeRepositoryAlreadyExistsException {
@@ -177,15 +132,6 @@ func ensureRepoExists(svc *ecr.ECR, name string, scanOnPush bool) (err error) {
return return
} }
func updateImageScannningConfig(svc *ecr.ECR, name string, scanOnPush bool) (err error) {
input := &ecr.PutImageScanningConfigurationInput{}
input.SetRepositoryName(name)
input.SetImageScanningConfiguration(&ecr.ImageScanningConfiguration{ScanOnPush: &scanOnPush})
_, err = svc.PutImageScanningConfiguration(input)
return err
}
func uploadLifeCyclePolicy(svc *ecr.ECR, lifecyclePolicy string, name string) (err error) { func uploadLifeCyclePolicy(svc *ecr.ECR, lifecyclePolicy string, name string) (err error) {
input := &ecr.PutLifecyclePolicyInput{} input := &ecr.PutLifecyclePolicyInput{}
input.SetLifecyclePolicyText(lifecyclePolicy) input.SetLifecyclePolicyText(lifecyclePolicy)
@@ -231,7 +177,7 @@ func parseBoolOrDefault(defaultValue bool, s string) (result bool) {
var err error var err error
result, err = strconv.ParseBool(s) result, err = strconv.ParseBool(s)
if err != nil { if err != nil {
result = defaultValue result = false
} }
return return
@@ -247,55 +193,11 @@ func getenv(key ...string) (s string) {
return return
} }
func getECRClient(sess *session.Session, role string, externalId string, idToken string) *ecr.ECR { func getECRClient(sess *session.Session, role string) *ecr.ECR {
if role == "" { if role == "" {
return ecr.New(sess) return ecr.New(sess)
} }
return ecr.New(sess, &aws.Config{
if idToken != "" { Credentials: stscreds.NewCredentials(sess, role),
tempFile, err := os.CreateTemp("/tmp", "idToken-*.jwt") })
if err != nil {
log.Fatalf("Failed to create temporary file: %v", err)
}
defer tempFile.Close()
if err := os.Chmod(tempFile.Name(), 0600); err != nil {
log.Fatalf("Failed to set file permissions: %v", err)
}
if _, err := tempFile.WriteString(idToken); err != nil {
log.Fatalf("Failed to write ID token to temporary file: %v", err)
}
// Create credentials using the path to the ID token file
creds := stscreds.NewWebIdentityCredentials(sess, role, "", tempFile.Name())
return ecr.New(sess, &aws.Config{Credentials: creds})
} else if externalId != "" {
return ecr.New(sess, &aws.Config{
Credentials: stscreds.NewCredentials(sess, role, func(p *stscreds.AssumeRoleProvider) {
p.ExternalID = &externalId
}),
})
} else {
return ecr.New(sess, &aws.Config{
Credentials: stscreds.NewCredentials(sess, role),
})
}
}
func tagExists(svc ecrAPI, repository, tag string) (bool, error) {
input := &ecr.DescribeImagesInput{
RepositoryName: aws.String(repository),
ImageIds: []*ecr.ImageIdentifier{
{ImageTag: aws.String(tag)},
},
}
output, err := svc.DescribeImages(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "ImageNotFoundException" {
return false, nil
}
return false, err
}
return len(output.ImageDetails) > 0, nil
} }
-165
View File
@@ -1,165 +0,0 @@
package main
import (
"context"
"encoding/base64"
"fmt"
"log"
"os"
"os/exec"
"path"
"strconv"
"strings"
docker "github.com/drone-plugins/drone-docker"
"github.com/drone-plugins/drone-docker/internal/gcp"
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
type Config struct {
Repo string
Registry string
Password string
WorkloadIdentity bool
Username string
AccessToken string
}
type staticTokenSource struct {
token *oauth2.Token
}
func (s *staticTokenSource) Token() (*oauth2.Token, error) {
return s.token, nil
}
func loadConfig() Config {
// Default username
username := "_json_key"
var config Config
// Load env-file if it exists
if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" {
if err := godotenv.Load(env); err != nil {
log.Fatalf("Error loading .env file: %v", err)
}
}
idToken := getenv("PLUGIN_OIDC_TOKEN_ID")
projectId := getenv("PLUGIN_PROJECT_NUMBER")
poolId := getenv("PLUGIN_POOL_ID")
providerId := getenv("PLUGIN_PROVIDER_ID")
serviceAccountEmail := getenv("PLUGIN_SERVICE_ACCOUNT_EMAIL")
if idToken != "" && projectId != "" && poolId != "" && providerId != "" && serviceAccountEmail != "" {
federalToken, err := gcp.GetFederalToken(idToken, projectId, poolId, providerId)
if err != nil {
logrus.Fatalf("Error (getFederalToken): %s", err)
}
accessToken, err := gcp.GetGoogleCloudAccessToken(federalToken, serviceAccountEmail)
if err != nil {
logrus.Fatalf("Error (getGoogleCloudAccessToken): %s", err)
}
config.AccessToken = accessToken
} else {
password := getenv(
"PLUGIN_JSON_KEY",
"GCR_JSON_KEY",
"GOOGLE_CREDENTIALS",
"TOKEN",
)
config.WorkloadIdentity = parseBoolOrDefault(false, getenv("PLUGIN_WORKLOAD_IDENTITY"))
config.Username, config.Password = setUsernameAndPassword(username, password, config.WorkloadIdentity)
}
location := getenv("PLUGIN_LOCATION")
repo := getenv("PLUGIN_REPO")
registry := getenv("PLUGIN_REGISTRY")
if registry == "" {
registry = fmt.Sprintf("%s-docker.pkg.dev", location)
}
if !strings.HasPrefix(repo, registry) {
repo = path.Join(registry, repo)
}
config.Repo = repo
config.Registry = registry
return config
}
func main() {
config := loadConfig()
if config.AccessToken != "" {
os.Setenv("ACCESS_TOKEN", config.AccessToken)
} else if config.Username != "" && config.Password != "" {
os.Setenv("DOCKER_USERNAME", config.Username)
os.Setenv("DOCKER_PASSWORD", config.Password)
}
os.Setenv("PLUGIN_REPO", config.Repo)
os.Setenv("PLUGIN_REGISTRY", config.Registry)
// invoke the base docker plugin binary
cmd := exec.Command(docker.GetDroneDockerExecCmd())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
logrus.Fatal(err)
}
}
func getOauthToken(data []byte) (s string) {
scopes := []string{
"https://www.googleapis.com/auth/cloud-platform",
}
ctx := context.Background()
credentials, err := google.CredentialsFromJSON(ctx, data, scopes...)
if err == nil {
token, err := credentials.TokenSource.Token()
if err == nil {
return token.AccessToken
}
}
return
}
func setUsernameAndPassword(user string, pass string, workloadIdentity bool) (u string, p string) {
// decode the token if base64 encoded
decoded, err := base64.StdEncoding.DecodeString(pass)
if err == nil {
pass = string(decoded)
}
// get oauth token and set username if using workload identity
if workloadIdentity {
data := []byte(pass)
pass = getOauthToken(data)
user = "oauth2accesstoken"
}
return user, pass
}
func parseBoolOrDefault(defaultValue bool, s string) (result bool) {
var err error
result, err = strconv.ParseBool(s)
if err != nil {
result = defaultValue
}
return
}
func getenv(key ...string) (s string) {
for _, k := range key {
s = os.Getenv(k)
if s != "" {
return
}
}
return
}
+26 -110
View File
@@ -1,152 +1,68 @@
package main package main
import ( import (
"context"
"encoding/base64" "encoding/base64"
"log"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"strconv"
"strings" "strings"
docker "github.com/drone-plugins/drone-docker"
"github.com/drone-plugins/drone-docker/internal/gcp"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2/google"
) )
type Config struct { // gcr default username
Repo string const username = "_json_key"
Registry string
Password string
WorkloadIdentity bool
Username string
AccessToken string
}
func loadConfig() Config { func main() {
// Default username // Load env-file if it exists first
username := "_json_key"
var config Config
// Load env-file if it exists
if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" { if env := os.Getenv("PLUGIN_ENV_FILE"); env != "" {
if err := godotenv.Load(env); err != nil { godotenv.Load(env)
log.Fatalf("Error loading .env file: %v", err)
}
} }
idToken := getenv("PLUGIN_OIDC_TOKEN_ID") var (
projectId := getenv("PLUGIN_PROJECT_NUMBER") repo = getenv("PLUGIN_REPO")
poolId := getenv("PLUGIN_POOL_ID") registry = getenv("PLUGIN_REGISTRY")
providerId := getenv("PLUGIN_PROVIDER_ID") password = getenv(
serviceAccountEmail := getenv("PLUGIN_SERVICE_ACCOUNT_EMAIL")
if idToken != "" && projectId != "" && poolId != "" && providerId != "" && serviceAccountEmail != "" {
federalToken, err := gcp.GetFederalToken(idToken, projectId, poolId, providerId)
if err != nil {
logrus.Fatalf("Error (getFederalToken): %s", err)
}
accessToken, err := gcp.GetGoogleCloudAccessToken(federalToken, serviceAccountEmail)
if err != nil {
logrus.Fatalf("Error (getGoogleCloudAccessToken): %s", err)
}
config.AccessToken = accessToken
} else {
password := getenv(
"PLUGIN_JSON_KEY", "PLUGIN_JSON_KEY",
"GCR_JSON_KEY", "GCR_JSON_KEY",
"GOOGLE_CREDENTIALS", "GOOGLE_CREDENTIALS",
"TOKEN", "TOKEN",
) )
config.WorkloadIdentity = parseBoolOrDefault(false, getenv("PLUGIN_WORKLOAD_IDENTITY")) )
config.Username, config.Password = setUsernameAndPassword(username, password, config.WorkloadIdentity)
// decode the token if base64 encoded
decoded, err := base64.StdEncoding.DecodeString(password)
if err == nil {
password = string(decoded)
} }
repo := getenv("PLUGIN_REPO") // default registry value
registryType := getenv("PLUGIN_REGISTRY_TYPE")
if registryType == "" {
registryType = "GCR"
}
registry := getenv("PLUGIN_REGISTRY")
if registry == "" { if registry == "" {
registry = "gcr.io" registry = "gcr.io"
} }
// must use the fully qualified repo name. If the
// repo name does not have the registry prefix we
// should prepend.
if !strings.HasPrefix(repo, registry) { if !strings.HasPrefix(repo, registry) {
repo = path.Join(registry, repo) repo = path.Join(registry, repo)
} }
config.Repo = repo
config.Registry = registry
return config
}
func main() { os.Setenv("PLUGIN_REPO", repo)
config := loadConfig() os.Setenv("PLUGIN_REGISTRY", registry)
if config.AccessToken != "" { os.Setenv("DOCKER_USERNAME", username)
os.Setenv("ACCESS_TOKEN", config.AccessToken) os.Setenv("DOCKER_PASSWORD", password)
} else if config.Username != "" && config.Password != "" {
os.Setenv("DOCKER_USERNAME", config.Username)
os.Setenv("DOCKER_PASSWORD", config.Password)
}
os.Setenv("PLUGIN_REPO", config.Repo)
os.Setenv("PLUGIN_REGISTRY", config.Registry)
// invoke the base docker plugin binary // invoke the base docker plugin binary
cmd := exec.Command(docker.GetDroneDockerExecCmd()) cmd := exec.Command("drone-docker")
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
err := cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
logrus.Fatal(err) os.Exit(1)
} }
} }
func getOauthToken(data []byte) (s string) {
scopes := []string{
"https://www.googleapis.com/auth/cloud-platform",
}
ctx := context.Background()
credentials, err := google.CredentialsFromJSON(ctx, data, scopes...)
if err == nil {
token, err := credentials.TokenSource.Token()
if err == nil {
return token.AccessToken
}
}
return
}
func setUsernameAndPassword(user string, pass string, workloadIdentity bool) (u string, p string) {
// decode the token if base64 encoded
decoded, err := base64.StdEncoding.DecodeString(pass)
if err == nil {
pass = string(decoded)
}
// get oauth token and set username if using workload identity
if workloadIdentity {
data := []byte(pass)
pass = getOauthToken(data)
user = "oauth2accesstoken"
}
return user, pass
}
func parseBoolOrDefault(defaultValue bool, s string) (result bool) {
var err error
result, err = strconv.ParseBool(s)
if err != nil {
result = defaultValue
}
return
}
func getenv(key ...string) (s string) { func getenv(key ...string) (s string) {
for _, k := range key { for _, k := range key {
s = os.Getenv(k) s = os.Getenv(k)
+3 -5
View File
@@ -1,17 +1,15 @@
//go:build !windows
// +build !windows // +build !windows
package docker package docker
import ( import (
"io" "io/ioutil"
"os" "os"
) )
const dockerExe = "/usr/local/bin/docker" const dockerExe = "/usr/local/bin/docker"
const dockerdExe = "/usr/local/bin/dockerd" const dockerdExe = "/usr/local/bin/dockerd"
const dockerHome = "/root/.docker/" const dockerHome = "/root/.docker/"
const cosignExe = "/usr/local/bin/cosign"
func (p Plugin) startDaemon() { func (p Plugin) startDaemon() {
cmd := commandDaemon(p.Daemon) cmd := commandDaemon(p.Daemon)
@@ -19,8 +17,8 @@ func (p Plugin) startDaemon() {
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
} else { } else {
cmd.Stdout = io.Discard cmd.Stdout = ioutil.Discard
cmd.Stderr = io.Discard cmd.Stderr = ioutil.Discard
} }
go func() { go func() {
trace(cmd) trace(cmd)
-2
View File
@@ -1,4 +1,3 @@
//go:build windows
// +build windows // +build windows
package docker package docker
@@ -6,7 +5,6 @@ package docker
const dockerExe = "C:\\bin\\docker.exe" const dockerExe = "C:\\bin\\docker.exe"
const dockerdExe = "" const dockerdExe = ""
const dockerHome = "C:\\ProgramData\\docker\\" const dockerHome = "C:\\ProgramData\\docker\\"
const cosignExe = "C:\\bin\\cosign.exe"
func (p Plugin) startDaemon() { func (p Plugin) startDaemon() {
// this is a no-op on windows // this is a no-op on windows
+79 -528
View File
@@ -1,128 +1,71 @@
package docker package docker
import ( import (
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"time" "time"
"github.com/drone-plugins/drone-docker/internal/docker"
"github.com/drone-plugins/drone-plugin-lib/drone"
) )
type ( type (
// Daemon defines Docker daemon parameters. // Daemon defines Docker daemon parameters.
Daemon struct { Daemon struct {
Registry string // Docker registry Registry string // Docker registry
Mirror string // Docker registry mirror Mirror string // Docker registry mirror
Insecure bool // Docker daemon enable insecure registries Insecure bool // Docker daemon enable insecure registries
StorageDriver string // Docker daemon storage driver StorageDriver string // Docker daemon storage driver
StoragePath string // Docker daemon storage path StoragePath string // Docker daemon storage path
Disabled bool // DOcker daemon is disabled (already running) Disabled bool // DOcker daemon is disabled (already running)
Debug bool // Docker daemon started in debug mode Debug bool // Docker daemon started in debug mode
Bip string // Docker daemon network bridge IP address Bip string // Docker daemon network bridge IP address
DNS []string // Docker daemon dns server DNS []string // Docker daemon dns server
DNSSearch []string // Docker daemon dns search domain DNSSearch []string // Docker daemon dns search domain
MTU string // Docker daemon mtu setting MTU string // Docker daemon mtu setting
IPv6 bool // Docker daemon IPv6 networking IPv6 bool // Docker daemon IPv6 networking
Experimental bool // Docker daemon enable experimental mode Experimental bool // Docker daemon enable experimental mode
RegistryType drone.RegistryType // Docker registry type
} }
// Login defines Docker login parameters. // Login defines Docker login parameters.
Login struct { Login struct {
Registry string // Docker registry address Registry string // Docker registry address
Username string // Docker registry username Username string // Docker registry username
Password string // Docker registry password Password string // Docker registry password
Email string // Docker registry email Email string // Docker registry email
Config string // Docker Auth Config Config string // Docker Auth Config
AccessToken string // External Access Token
} }
// Build defines Docker build parameters. // Build defines Docker build parameters.
Build struct { Build struct {
Remote string // Git remote URL Remote string // Git remote URL
Name string // Docker build using default named tag Name string // Docker build using default named tag
TempTag string // Temporary tag used during docker build Dockerfile string // Docker build Dockerfile
Dockerfile string // Docker build Dockerfile Context string // Docker build context
Context string // Docker build context Tags []string // Docker build tags
Tags []string // Docker build tags Args []string // Docker build args
Args []string // Docker build args ArgsEnv []string // Docker build args from env
ArgsEnv []string // Docker build args from env Target string // Docker build target
ArgsNew []string // docker build args which has comma seperated values Squash bool // Docker build squash
IsMultipleBuildArgs bool // env variable for fall back to old build args Pull bool // Docker build pull
Target string // Docker build target CacheFrom []string // Docker build cache-from
Squash bool // Docker build squash Compress bool // Docker build compress
Pull bool // Docker build pull Repo string // Docker build repository
CacheFrom []string // Docker build cache-from LabelSchema []string // label-schema Label map
Compress bool // Docker build compress Labels []string // Label map
Repo string // Docker build repository NoCache bool // Docker build no-cache
LabelSchema []string // label-schema Label map AddHost []string // Docker build add-host
AutoLabel bool // auto-label bool Quiet bool // Docker build quiet
Labels []string // Label map
Link string // Git repo link
NoCache bool // Docker build no-cache
Secret string // secret keypair
SecretEnvs []string // Docker build secrets with env var as source
SecretFiles []string // Docker build secrets with file as source
AddHost []string // Docker build add-host
Quiet bool // Docker build quiet
Platform string // Docker build platform
SSHAgentKey string // Docker build ssh agent key
SSHKeyPath string // Docker build ssh key path
}
// CosignConfig defines Cosign signing parameters.
CosignConfig struct {
PrivateKey string // Private key content (PEM format) or file path
Password string // Password for encrypted private keys
Params string // Additional cosign parameters
} }
// Plugin defines the Docker plugin parameters. // Plugin defines the Docker plugin parameters.
Plugin struct { Plugin struct {
Login Login // Docker login configuration Login Login // Docker login configuration
Build Build // Docker build configuration Build Build // Docker build configuration
Daemon Daemon // Docker daemon configuration Daemon Daemon // Docker daemon configuration
Cosign CosignConfig // Cosign signing configuration Dryrun bool // Docker push is skipped
Dryrun bool // Docker push is skipped Cleanup bool // Docker purge is enabled
Cleanup bool // Docker purge is enabled
CardPath string // Card path to write file to
ArtifactFile string // Artifact path to write file to
BaseImageRegistry string // Docker registry to pull base image
BaseImageUsername string // Docker registry username to pull base image
BaseImagePassword string // Docker registry password to pull base image
}
Card []struct {
ID string `json:"Id"`
RepoTags []string `json:"RepoTags"`
ParsedRepoTags []TagStruct `json:"ParsedRepoTags"`
RepoDigests []interface{} `json:"RepoDigests"`
Parent string `json:"Parent"`
Comment string `json:"Comment"`
Created time.Time `json:"Created"`
Container string `json:"Container"`
DockerVersion string `json:"DockerVersion"`
Author string `json:"Author"`
Architecture string `json:"Architecture"`
Os string `json:"Os"`
Size int `json:"Size"`
VirtualSize int `json:"VirtualSize"`
Metadata struct {
LastTagTime time.Time `json:"LastTagTime"`
} `json:"Metadata"`
SizeString string
VirtualSizeString string
Time string
URL string `json:"URL"`
}
TagStruct struct {
Tag string `json:"Tag"`
} }
) )
@@ -135,100 +78,44 @@ func (p Plugin) Exec() error {
// poll the docker daemon until it is started. This ensures the daemon is // poll the docker daemon until it is started. This ensures the daemon is
// ready to accept connections before we proceed. // ready to accept connections before we proceed.
for i := 0; ; i++ { for i := 0; i < 15; i++ {
cmd := commandInfo() cmd := commandInfo()
err := cmd.Run() err := cmd.Run()
if err == nil { if err == nil {
break break
} }
if i == 15 {
fmt.Println("Unable to reach Docker Daemon after 15 attempts.")
break
}
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
} }
// for debugging purposes, log the type of authentication // Create Auth Config File
// credentials that have been provided.
switch {
case p.Login.Password != "" && p.Login.Config != "":
fmt.Println("Detected registry credentials and registry credentials file")
case p.Login.Password != "":
fmt.Println("Detected registry credentials")
case p.Login.Config != "":
fmt.Println("Detected registry credentials file")
case p.Login.AccessToken != "":
fmt.Println("Detected access token")
default:
fmt.Println("Registry credentials or Docker config not provided. Guest mode enabled.")
}
// create Auth Config File
if p.Login.Config != "" { if p.Login.Config != "" {
os.MkdirAll(dockerHome, 0600) os.MkdirAll(dockerHome, 0600)
path := filepath.Join(dockerHome, "config.json") path := filepath.Join(dockerHome, "config.json")
err := os.WriteFile(path, []byte(p.Login.Config), 0600) err := ioutil.WriteFile(path, []byte(p.Login.Config), 0600)
if err != nil { if err != nil {
return fmt.Errorf("Error writing config.json: %s", err) return fmt.Errorf("Error writeing config.json: %s", err)
} }
} }
// instead of writing to config file directly, using docker's login func
// is better to integrate with various credential helpers,
// it also handles different registry specific logic in a better way,
// as opposed to config write where different registries need to be addressed differently.
// It handles any changes in the authentication process across different Docker versions.
if p.BaseImageRegistry != "" {
if p.BaseImageUsername == "" {
fmt.Printf("Username cannot be empty. The base image connector requires authenticated access. Please either use an authenticated connector, or remove the base image connector.")
}
if p.BaseImagePassword == "" {
fmt.Printf("Password cannot be empty. The base image connector requires authenticated access. Please either use an authenticated connector, or remove the base image connector.")
}
var baseConnectorLogin Login
baseConnectorLogin.Registry = p.BaseImageRegistry
baseConnectorLogin.Username = p.BaseImageUsername
baseConnectorLogin.Password = p.BaseImagePassword
cmd := commandLogin(baseConnectorLogin)
raw, err := cmd.CombinedOutput()
if err != nil {
out := string(raw)
out = strings.Replace(out, "WARNING! Using --password via the CLI is insecure. Use --password-stdin.", "", -1)
fmt.Println(out)
return fmt.Errorf("Error authenticating base connector: exit status 1")
}
} else {
fmt.Println("\033[33mTo ensure consistent and reliable pipeline execution, we recommend setting up a Base Image Connector.\033[0m\n" +
"\033[33mWhile optional at this time, configuring it helps prevent failures caused by Docker Hub's rate limits.\033[0m")
}
// login to the Docker registry // login to the Docker registry
if p.Login.Password != "" { if p.Login.Password != "" {
cmd := commandLogin(p.Login) cmd := commandLogin(p.Login)
raw, err := cmd.CombinedOutput() err := cmd.Run()
if err != nil { if err != nil {
out := string(raw) return fmt.Errorf("Error authenticating: %s", err)
out = strings.Replace(out, "WARNING! Using --password via the CLI is insecure. Use --password-stdin.", "", -1)
fmt.Println(out)
return fmt.Errorf("error authenticating: exit status 1")
}
} else if p.Login.AccessToken != "" {
cmd := commandLoginAccessToken(p.Login, p.Login.AccessToken)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error logging in to Docker registry: %s", err)
}
if strings.Contains(string(output), "Login Succeeded") {
fmt.Println("Login successful")
} else {
return fmt.Errorf("login did not succeed")
} }
} }
switch {
case p.Login.Password != "":
fmt.Println("Detected registry credentials")
case p.Login.Config != "":
fmt.Println("Detected registry credentials file")
default:
fmt.Println("Registry credentials or Docker config not provided. Guest mode enabled.")
}
if p.Build.Squash && !p.Daemon.Experimental { if p.Build.Squash && !p.Daemon.Experimental {
fmt.Println("Squash build flag is only available when Docker deamon is started with experimental flag. Ignoring...") fmt.Println("Squash build flag is only available when Docker deamon is started with experimental flag. Ignoring...")
p.Build.Squash = false p.Build.Squash = false
@@ -246,33 +133,21 @@ func (p Plugin) Exec() error {
cmds = append(cmds, commandPull(img)) cmds = append(cmds, commandPull(img))
} }
// setup for using ssh agent (https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds)
if p.Build.SSHAgentKey != "" {
var sshErr error
p.Build.SSHKeyPath, sshErr = writeSSHPrivateKey(p.Build.SSHAgentKey)
if sshErr != nil {
return sshErr
}
}
cmds = append(cmds, commandBuild(p.Build)) // docker build cmds = append(cmds, commandBuild(p.Build)) // docker build
// Validate cosign configuration if present
if p.shouldSignWithCosign() {
if err := validateCosignConfig(p.Cosign); err != nil {
return fmt.Errorf("cosign validation failed: %w", err)
}
fmt.Println("🔐 Cosign signing enabled - images will be signed after push")
}
for _, tag := range p.Build.Tags { for _, tag := range p.Build.Tags {
cmds = append(cmds, commandTag(p.Build, tag)) // docker tag cmds = append(cmds, commandTag(p.Build, tag)) // docker tag
if !p.Dryrun { if p.Dryrun == false {
cmds = append(cmds, commandPush(p.Build, tag)) // docker push cmds = append(cmds, commandPush(p.Build, tag)) // docker push
} }
} }
if p.Cleanup {
cmds = append(cmds, commandRmi(p.Build.Name)) // docker rmi
cmds = append(cmds, commandPrune()) // docker system prune -f
}
// execute all commands in batch mode. // execute all commands in batch mode.
for _, cmd := range cmds { for _, cmd := range cmds {
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@@ -291,93 +166,9 @@ func (p Plugin) Exec() error {
} }
} }
// output the adaptive card
if err := p.writeCard(); err != nil {
fmt.Printf("Could not create adaptive card. %s\n", err)
}
if p.ArtifactFile != "" {
if digest, err := getDigest(p.Build.TempTag); err == nil {
if err = drone.WritePluginArtifactFile(p.Daemon.RegistryType, p.ArtifactFile, p.Daemon.Registry, p.Build.Repo, digest, p.Build.Tags); err != nil {
fmt.Printf("failed to write plugin artifact file at path: %s with error: %s\n", p.ArtifactFile, err)
}
} else {
fmt.Printf("Could not fetch the digest. %s\n", err)
}
}
// Handle cosign signing after all commands complete (like artifact generation)
if p.shouldSignWithCosign() && !p.Dryrun {
// Set up environment variables for cosign
os.Setenv("COSIGN_YES", "true")
if digest, err := getDigest(p.Build.TempTag); err == nil {
fmt.Printf("🔐 Found image digest: %s\n", digest)
// Sign with digest reference
imageRef := fmt.Sprintf("%s@%s", p.Build.Repo, digest)
cosignCmd := createCosignCommand(imageRef, p.Cosign)
executeCosignCommand(cosignCmd)
} else {
fmt.Printf("⚠️ WARNING: Could not get image digest for cosign signing: %s\n", err)
fmt.Printf(" Falling back to tag-based signing\n")
// Fall back to tag-based signing for each tag
for _, tag := range p.Build.Tags {
imageRef := fmt.Sprintf("%s:%s", p.Build.Repo, tag)
cosignCmd := createCosignCommand(imageRef, p.Cosign)
executeCosignCommand(cosignCmd)
}
}
}
// execute cleanup routines in batch mode
if p.Cleanup {
// clear the slice
cmds = nil
cmds = append(cmds, commandRmi(p.Build.TempTag)) // docker rmi
cmds = append(cmds, commandPrune()) // docker system prune -f
for _, cmd := range cmds {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
trace(cmd)
}
}
return nil return nil
} }
// helper function to set the credentials
func setDockerAuth(username, password, registry, baseImageUsername,
baseImagePassword, baseImageRegistry string) ([]byte, error) {
var credentials []docker.RegistryCredentials
// add only docker registry to the config
dockerConfig := docker.NewConfig()
if password != "" {
pushToRegistryCreds := docker.RegistryCredentials{
Registry: registry,
Username: username,
Password: password,
}
// push registry auth
credentials = append(credentials, pushToRegistryCreds)
}
if baseImageRegistry != "" {
pullFromRegistryCreds := docker.RegistryCredentials{
Registry: baseImageRegistry,
Username: baseImageUsername,
Password: baseImagePassword,
}
// base image registry auth
credentials = append(credentials, pullFromRegistryCreds)
}
// Creates docker config for both the registries used for authentication
return dockerConfig.CreateDockerConfigJson(credentials)
}
// helper function to create the docker login command. // helper function to create the docker login command.
func commandLogin(login Login) *exec.Cmd { func commandLogin(login Login) *exec.Cmd {
if login.Email != "" { if login.Email != "" {
@@ -391,17 +182,6 @@ func commandLogin(login Login) *exec.Cmd {
) )
} }
func commandLoginAccessToken(login Login, accessToken string) *exec.Cmd {
cmd := exec.Command(dockerExe,
"login",
"-u",
"oauth2accesstoken",
"--password-stdin",
login.Registry)
cmd.Stdin = strings.NewReader(accessToken)
return cmd
}
// helper to check if args match "docker pull <image>" // helper to check if args match "docker pull <image>"
func isCommandPull(args []string) bool { func isCommandPull(args []string) bool {
return len(args) > 2 && args[1] == "pull" return len(args) > 2 && args[1] == "pull"
@@ -437,7 +217,7 @@ func commandBuild(build Build) *exec.Cmd {
"build", "build",
"--rm=true", "--rm=true",
"-f", build.Dockerfile, "-f", build.Dockerfile,
"-t", build.TempTag, "-t", build.Name,
} }
args = append(args, build.Context) args = append(args, build.Context)
@@ -459,60 +239,32 @@ func commandBuild(build Build) *exec.Cmd {
for _, arg := range build.ArgsEnv { for _, arg := range build.ArgsEnv {
addProxyValue(&build, arg) addProxyValue(&build, arg)
} }
if build.IsMultipleBuildArgs { for _, arg := range build.Args {
for _, arg := range build.ArgsNew { args = append(args, "--build-arg", arg)
args = append(args, "--build-arg", arg)
}
} else {
for _, arg := range build.Args {
args = append(args, "--build-arg", arg)
}
} }
for _, host := range build.AddHost { for _, host := range build.AddHost {
args = append(args, "--add-host", host) args = append(args, "--add-host", host)
} }
if build.Secret != "" {
args = append(args, "--secret", build.Secret)
}
for _, secret := range build.SecretEnvs {
if arg, err := getSecretStringCmdArg(secret); err == nil {
args = append(args, "--secret", arg)
}
}
for _, secret := range build.SecretFiles {
if arg, err := getSecretFileCmdArg(secret); err == nil {
args = append(args, "--secret", arg)
}
}
if build.Target != "" { if build.Target != "" {
args = append(args, "--target", build.Target) args = append(args, "--target", build.Target)
} }
if build.Quiet { if build.Quiet {
args = append(args, "--quiet") args = append(args, "--quiet")
} }
if build.Platform != "" {
args = append(args, "--platform", build.Platform) labelSchema := []string{
} "schema-version=1.0",
if build.SSHKeyPath != "" { fmt.Sprintf("build-date=%s", time.Now().Format(time.RFC3339)),
args = append(args, "--ssh", build.SSHKeyPath) fmt.Sprintf("vcs-ref=%s", build.Name),
fmt.Sprintf("vcs-url=%s", build.Remote),
} }
if build.AutoLabel { if len(build.LabelSchema) > 0 {
labelSchema := []string{ labelSchema = append(labelSchema, build.LabelSchema...)
fmt.Sprintf("created=%s", time.Now().Format(time.RFC3339)), }
fmt.Sprintf("revision=%s", build.Name),
fmt.Sprintf("source=%s", build.Remote),
fmt.Sprintf("url=%s", build.Link),
}
labelPrefix := "org.opencontainers.image"
if len(build.LabelSchema) > 0 { for _, label := range labelSchema {
labelSchema = append(labelSchema, build.LabelSchema...) args = append(args, "--label", fmt.Sprintf("org.label-schema.%s", label))
}
for _, label := range labelSchema {
args = append(args, "--label", fmt.Sprintf("%s.%s", labelPrefix, label))
}
} }
if len(build.Labels) > 0 { if len(build.Labels) > 0 {
@@ -521,41 +273,9 @@ func commandBuild(build Build) *exec.Cmd {
} }
} }
// we need to enable buildkit, for secret support and ssh agent support
if build.Secret != "" || len(build.SecretEnvs) > 0 || len(build.SecretFiles) > 0 || build.SSHAgentKey != "" {
os.Setenv("DOCKER_BUILDKIT", "1")
}
return exec.Command(dockerExe, args...) return exec.Command(dockerExe, args...)
} }
func getSecretStringCmdArg(kvp string) (string, error) {
return getSecretCmdArg(kvp, false)
}
func getSecretFileCmdArg(kvp string) (string, error) {
return getSecretCmdArg(kvp, true)
}
func getSecretCmdArg(kvp string, file bool) (string, error) {
delimIndex := strings.IndexByte(kvp, '=')
if delimIndex == -1 {
return "", fmt.Errorf("%s is not a valid secret", kvp)
}
key := kvp[:delimIndex]
value := kvp[delimIndex+1:]
if key == "" || value == "" {
return "", fmt.Errorf("%s is not a valid secret", kvp)
}
if file {
return fmt.Sprintf("id=%s,src=%s", key, value), nil
}
return fmt.Sprintf("id=%s,env=%s", key, value), nil
}
// helper function to add proxy values from the environment // helper function to add proxy values from the environment
func addProxyBuildArgs(build *Build) { func addProxyBuildArgs(build *Build) {
addProxyValue(build, "http_proxy") addProxyValue(build, "http_proxy")
@@ -571,10 +291,6 @@ func addProxyValue(build *Build, key string) {
build.Args = append(build.Args, fmt.Sprintf("%s=%s", key, value)) build.Args = append(build.Args, fmt.Sprintf("%s=%s", key, value))
build.Args = append(build.Args, fmt.Sprintf("%s=%s", strings.ToUpper(key), value)) build.Args = append(build.Args, fmt.Sprintf("%s=%s", strings.ToUpper(key), value))
} }
if len(value) > 0 && !hasProxyBuildArgNew(build, key) {
build.ArgsNew = append(build.ArgsNew, fmt.Sprintf("%s=%s", key, value))
build.ArgsNew = append(build.ArgsNew, fmt.Sprintf("%s=%s", strings.ToUpper(key), value))
}
} }
// helper function to get a proxy value from the environment. // helper function to get a proxy value from the environment.
@@ -602,22 +318,11 @@ func hasProxyBuildArg(build *Build, key string) bool {
return false return false
} }
func hasProxyBuildArgNew(build *Build, key string) bool {
keyUpper := strings.ToUpper(key)
for _, s := range build.ArgsNew {
if strings.HasPrefix(s, key) || strings.HasPrefix(s, keyUpper) {
return true
}
}
return false
}
// helper function to create the docker tag command. // helper function to create the docker tag command.
func commandTag(build Build, tag string) *exec.Cmd { func commandTag(build Build, tag string) *exec.Cmd {
var ( var (
source = build.TempTag source = build.Name
target = fmt.Sprintf("%s:%s", build.Repo, tag) target = fmt.Sprintf("%s:%s", build.Repo, tag)
) )
return exec.Command( return exec.Command(
@@ -638,10 +343,6 @@ func commandDaemon(daemon Daemon) *exec.Cmd {
"--host=unix:///var/run/docker.sock", "--host=unix:///var/run/docker.sock",
} }
if _, err := os.Stat("/etc/docker/default.json"); err == nil {
args = append(args, "--seccomp-profile=/etc/docker/default.json")
}
if daemon.StorageDriver != "" { if daemon.StorageDriver != "" {
args = append(args, "-s", daemon.StorageDriver) args = append(args, "-s", daemon.StorageDriver)
} }
@@ -672,6 +373,7 @@ func commandDaemon(daemon Daemon) *exec.Cmd {
return exec.Command(dockerdExe, args...) return exec.Command(dockerdExe, args...)
} }
// helper to check if args match "docker prune" // helper to check if args match "docker prune"
func isCommandPrune(args []string) bool { func isCommandPrune(args []string) bool {
return len(args) > 3 && args[2] == "prune" return len(args) > 3 && args[2] == "prune"
@@ -686,163 +388,12 @@ func isCommandRmi(args []string) bool {
return len(args) > 2 && args[1] == "rmi" return len(args) > 2 && args[1] == "rmi"
} }
// helper to check if args match "cosign sign"
func isCommandCosign(args []string) bool {
return len(args) > 1 && args[0] == cosignExe
}
func commandRmi(tag string) *exec.Cmd { func commandRmi(tag string) *exec.Cmd {
return exec.Command(dockerExe, "rmi", tag) return exec.Command(dockerExe, "rmi", tag)
} }
func writeSSHPrivateKey(key string) (path string, err error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("unable to determine home directory: %s", err)
}
if err := os.MkdirAll(filepath.Join(home, ".ssh"), 0700); err != nil {
return "", fmt.Errorf("unable to create .ssh directory: %s", err)
}
pathToKey := filepath.Join(home, ".ssh", "id_rsa")
if err := os.WriteFile(pathToKey, []byte(key), 0400); err != nil {
return "", fmt.Errorf("unable to write ssh key %s: %s", pathToKey, err)
}
path = fmt.Sprintf("default=%s", pathToKey)
return path, nil
}
// trace writes each command to stdout with the command wrapped in an xml // trace writes each command to stdout with the command wrapped in an xml
// tag so that it can be extracted and displayed in the logs. // tag so that it can be extracted and displayed in the logs.
func trace(cmd *exec.Cmd) { func trace(cmd *exec.Cmd) {
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " ")) fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
} }
func GetDroneDockerExecCmd() string {
if runtime.GOOS == "windows" {
return "C:/bin/drone-docker.exe"
}
return "drone-docker"
}
func getDigest(buildName string) (string, error) {
cmd := exec.Command(dockerExe, "inspect", "--format='{{index .RepoDigests 0}}'", buildName)
output, err := cmd.Output()
if err != nil {
return "", err
}
// Parse the output to extract the repo digest.
digest := strings.Trim(string(output), "'\n")
parts := strings.Split(digest, "@")
if len(parts) > 1 {
return parts[1], nil
}
return "", errors.New("unable to fetch digest")
}
// shouldSignWithCosign determines if cosign signing should be performed
func (p Plugin) shouldSignWithCosign() bool {
return p.Cosign.PrivateKey != ""
}
// validateCosignConfig validates the cosign configuration
func validateCosignConfig(config CosignConfig) error {
if config.PrivateKey == "" {
return nil // No cosign config, skip silently
}
// Check if cosign binary is available
if _, err := exec.LookPath(cosignExe); err != nil {
fmt.Printf("❌ ERROR: cosign binary not found at %s\n", cosignExe)
fmt.Println(" Ensure you're using a plugin image that includes cosign")
return fmt.Errorf("cosign binary not available: %w", err)
}
// Check if it's trying to use keyless signing
if strings.Contains(config.Params, "--oidc") ||
strings.Contains(config.Params, "--identity-token") {
fmt.Println("⚠️ WARNING: Keyless signing (OIDC) isn't supported yet in this plugin. Use private key signing instead.")
return errors.New("keyless signing not supported")
}
// Validate private key format if it's PEM content
if strings.HasPrefix(config.PrivateKey, "-----BEGIN") {
if !isValidPEMKey(config.PrivateKey) {
return errors.New("❌ Invalid private key format. Expected PEM format")
}
// Check encrypted key password requirement
if isEncryptedPEMKey(config.PrivateKey) && config.Password == "" {
return errors.New("🔐 Encrypted private key requires password. Set PLUGIN_COSIGN_PASSWORD")
}
} else {
// File-based key - check if it's accessible (basic check)
if _, err := os.Stat(config.PrivateKey); err != nil {
fmt.Printf("⚠️ WARNING: Private key file may not be accessible: %s\n", config.PrivateKey)
fmt.Println(" This will be verified during signing")
}
}
return nil
}
// isEncryptedPEMKey checks if a PEM key is encrypted
func isEncryptedPEMKey(pemContent string) bool {
return strings.Contains(pemContent, "ENCRYPTED")
}
// isValidPEMKey performs basic PEM format validation
func isValidPEMKey(pemContent string) bool {
return strings.Contains(pemContent, "-----BEGIN") &&
strings.Contains(pemContent, "-----END") &&
(strings.Contains(pemContent, "PRIVATE KEY") ||
strings.Contains(pemContent, "RSA PRIVATE KEY") ||
strings.Contains(pemContent, "EC PRIVATE KEY"))
}
// createCosignCommand creates a cosign sign command with the given image reference
func createCosignCommand(imageRef string, cosign CosignConfig) *exec.Cmd {
args := []string{"sign", "--yes"}
// Handle private key (content vs file path)
if strings.HasPrefix(cosign.PrivateKey, "-----BEGIN") {
args = append(args, "--key", "env://COSIGN_PRIVATE_KEY")
os.Setenv("COSIGN_PRIVATE_KEY", cosign.PrivateKey)
} else {
args = append(args, "--key", cosign.PrivateKey)
}
// Set password if provided
if cosign.Password != "" {
os.Setenv("COSIGN_PASSWORD", cosign.Password)
}
// Add any extra parameters
if cosign.Params != "" {
extraArgs := strings.Fields(cosign.Params)
args = append(args, extraArgs...)
}
// Add the image reference to sign
args = append(args, imageRef)
return exec.Command(cosignExe, args...)
}
// executeCosignCommand executes the given cosign command and handles errors
func executeCosignCommand(cmd *exec.Cmd) {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Printf("🚀 Executing: %s %s\n", cmd.Path, strings.Join(cmd.Args[1:], " "))
if err := cmd.Run(); err != nil {
fmt.Printf("⚠️ WARNING: Image signing failed: %s\n", err)
fmt.Printf(" Image was pushed successfully but could not be signed\n")
fmt.Printf(" This is not fatal - continuing with the build\n")
}
}
+4
View File
@@ -0,0 +1,4 @@
FROM plugins/docker:linux-arm
ADD release/linux/arm/drone-acr /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-acr"]
@@ -1,5 +1,5 @@
# escape=` # escape=`
FROM plugins/docker:windows-ltsc2022-amd64 FROM plugins/docker:windows-1903-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" ` LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ACR" ` org.label-schema.name="Drone ACR" `
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-1909-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ACR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-acr.exe C:/bin/drone-acr.exe
ENTRYPOINT [ "C:\\bin\\drone-acr.exe" ]
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-2004-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ACR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-acr.exe C:/bin/drone-acr.exe
ENTRYPOINT [ "C:\\bin\\drone-acr.exe" ]
+25 -12
View File
@@ -1,31 +1,44 @@
image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}} {{#if build.tags}}
tags: tags:
{{#each build.tags}} {{#each build.tags}}
- {{this}} - {{this}}
{{/each}} {{/each}}
{{/if}} {{/if}}
manifests: manifests:
- - image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- - image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform: platform:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
- - image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64 platform:
architecture: arm
os: linux
variant: v7
- image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-2004-amd64
platform:
architecture: amd64
os: windows
version: 2004
- image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1909-amd64
platform:
architecture: amd64
os: windows
version: 1909
- image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1903-amd64
platform:
architecture: amd64
os: windows
version: 1903
- image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: windows os: windows
version: 1809 version: 1809
-
image: plugins/acr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-ltsc2022-amd64
platform:
architecture: amd64
os: windows
version: ltsc2022
+1 -5
View File
@@ -1,10 +1,6 @@
FROM docker:28.1.1-dind FROM docker:19.03.8-dind
ENV DOCKER_HOST=unix:///var/run/docker.sock ENV DOCKER_HOST=unix:///var/run/docker.sock
# Install cosign for container image signing
RUN wget -O /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.5.3/cosign-linux-amd64 \
&& chmod +x /usr/local/bin/cosign
ADD release/linux/amd64/drone-docker /bin/ ADD release/linux/amd64/drone-docker /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-docker"] ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-docker"]
+6
View File
@@ -0,0 +1,6 @@
FROM arm32v6/docker:19.03.8-dind
ENV DOCKER_HOST=unix:///var/run/docker.sock
ADD release/linux/arm/drone-docker /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-docker"]
+1 -5
View File
@@ -1,10 +1,6 @@
FROM arm64v8/docker:28.1.1-dind FROM arm64v8/docker:19.03.8-dind
ENV DOCKER_HOST=unix:///var/run/docker.sock ENV DOCKER_HOST=unix:///var/run/docker.sock
# Install cosign for container image signing
RUN wget -O /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v2.5.3/cosign-linux-arm64 \
&& chmod +x /usr/local/bin/cosign
ADD release/linux/arm64/drone-docker /bin/ ADD release/linux/arm64/drone-docker /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-docker"] ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-docker"]
@@ -1,11 +1,11 @@
# escape=` # escape=`
FROM mcr.microsoft.com/windows/servercore:ltsc2022 as download FROM mcr.microsoft.com/windows/servercore:1809 as download
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV DOCKER_VERSION 19.03.1 ENV DOCKER_VERSION 19.03.1
RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.7-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; ` RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.9-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; `
Expand-Archive innoextract.zip -DestinationPath C:\ ; ` Expand-Archive innoextract.zip -DestinationPath C:\ ; `
Remove-Item -Path innoextract.zip Remove-Item -Path innoextract.zip
@@ -13,7 +13,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl
Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing
RUN /innoextract.exe dockertoolbox.exe RUN /innoextract.exe dockertoolbox.exe
FROM mcr.microsoft.com/windows/nanoserver:ltsc2022 FROM plugins/base:windows-1809-amd64
USER ContainerAdministrator USER ContainerAdministrator
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" ` LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
@@ -21,11 +21,6 @@ LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.vendor="Drone.IO Community" ` org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0" org.label-schema.schema-version="1.0"
RUN mkdir C:\bin
# Install cosign for container image signing
ADD https://github.com/sigstore/cosign/releases/download/v2.5.3/cosign-windows-amd64.exe C:/bin/cosign.exe
COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll
COPY --from=download /app/docker.exe C:/bin/docker.exe COPY --from=download /app/docker.exe C:/bin/docker.exe
ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe
@@ -1,12 +1,11 @@
# escape=` # escape=`
# using 1809-KB5021237-amd64 as base image, 1809-KB5022286-amd64 does not work FROM mcr.microsoft.com/windows/servercore:1903 as download
FROM mcr.microsoft.com/windows/servercore:1809-KB5021237 as download
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV DOCKER_VERSION 19.03.1 ENV DOCKER_VERSION 19.03.1
RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.6-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; ` RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.9-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; `
Expand-Archive innoextract.zip -DestinationPath C:\ ; ` Expand-Archive innoextract.zip -DestinationPath C:\ ; `
Remove-Item -Path innoextract.zip Remove-Item -Path innoextract.zip
@@ -14,8 +13,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl
Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing
RUN /innoextract.exe dockertoolbox.exe RUN /innoextract.exe dockertoolbox.exe
FROM mcr.microsoft.com/windows/nanoserver:1809-KB5021237-amd64 FROM plugins/base:windows-1903-amd64
USER ContainerAdministrator USER ContainerAdministrator
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" ` LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
@@ -23,11 +21,6 @@ LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.vendor="Drone.IO Community" ` org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0" org.label-schema.schema-version="1.0"
RUN mkdir C:\bin
# Install cosign for container image signing
ADD https://github.com/sigstore/cosign/releases/download/v2.5.3/cosign-windows-amd64.exe C:/bin/cosign.exe
COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll
COPY --from=download /app/docker.exe C:/bin/docker.exe COPY --from=download /app/docker.exe C:/bin/docker.exe
ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe
+27
View File
@@ -0,0 +1,27 @@
# escape=`
FROM mcr.microsoft.com/windows/servercore:1909 as download
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV DOCKER_VERSION 19.03.1
RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.9-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; `
Expand-Archive innoextract.zip -DestinationPath C:\ ; `
Remove-Item -Path innoextract.zip
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing
RUN /innoextract.exe dockertoolbox.exe
FROM plugins/base:windows-1909-amd64
USER ContainerAdministrator
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone Docker" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll
COPY --from=download /app/docker.exe C:/bin/docker.exe
ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe
ENTRYPOINT [ "C:\\bin\\drone-docker.exe" ]
+27
View File
@@ -0,0 +1,27 @@
# escape=`
FROM mcr.microsoft.com/windows/servercore:2004 as download
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV DOCKER_VERSION 19.03.1
RUN Invoke-WebRequest 'http://constexpr.org/innoextract/files/innoextract-1.9-windows.zip' -OutFile 'innoextract.zip' -UseBasicParsing ; `
Expand-Archive innoextract.zip -DestinationPath C:\ ; `
Remove-Item -Path innoextract.zip
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
Invoke-WebRequest $('https://github.com/docker/toolbox/releases/download/v{0}/DockerToolbox-{0}.exe' -f $env:DOCKER_VERSION) -OutFile 'dockertoolbox.exe' -UseBasicParsing
RUN /innoextract.exe dockertoolbox.exe
FROM plugins/base:windows-2004-amd64
USER ContainerAdministrator
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone Docker" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
COPY --from=download /windows/system32/netapi32.dll /windows/system32/netapi32.dll
COPY --from=download /app/docker.exe C:/bin/docker.exe
ADD release/windows/amd64/drone-docker.exe C:/bin/drone-docker.exe
ENTRYPOINT [ "C:\\bin\\drone-docker.exe" ]
+25 -12
View File
@@ -1,31 +1,44 @@
image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}} {{#if build.tags}}
tags: tags:
{{#each build.tags}} {{#each build.tags}}
- {{this}} - {{this}}
{{/each}} {{/each}}
{{/if}} {{/if}}
manifests: manifests:
- - image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- - image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform: platform:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
- - image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64 platform:
architecture: arm
os: linux
variant: v7
- image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-2004-amd64
platform:
architecture: amd64
os: windows
version: 2004
- image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1909-amd64
platform:
architecture: amd64
os: windows
version: 1909
- image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1903-amd64
platform:
architecture: amd64
os: windows
version: 1903
- image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: windows os: windows
version: 1809 version: 1809
-
image: plugins/docker:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-ltsc2022-amd64
platform:
architecture: amd64
os: windows
version: ltsc2022
+4
View File
@@ -0,0 +1,4 @@
FROM plugins/docker:linux-arm
ADD release/linux/arm/drone-ecr /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-ecr"]
@@ -1,5 +1,5 @@
# escape=` # escape=`
FROM plugins/docker:windows-ltsc2022-amd64 FROM plugins/docker:windows-1903-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" ` LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ECR" ` org.label-schema.name="Drone ECR" `
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-1909-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ECR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-ecr.exe C:/bin/drone-ecr.exe
ENTRYPOINT [ "C:\\bin\\drone-ecr.exe" ]
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-2004-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone ECR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-ecr.exe C:/bin/drone-ecr.exe
ENTRYPOINT [ "C:\\bin\\drone-ecr.exe" ]
+25 -12
View File
@@ -1,31 +1,44 @@
image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}} {{#if build.tags}}
tags: tags:
{{#each build.tags}} {{#each build.tags}}
- {{this}} - {{this}}
{{/each}} {{/each}}
{{/if}} {{/if}}
manifests: manifests:
- - image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- - image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform: platform:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
- - image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64 platform:
architecture: arm
os: linux
variant: v7
- image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-2004-amd64
platform:
architecture: amd64
os: windows
version: 2004
- image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1909-amd64
platform:
architecture: amd64
os: windows
version: 1909
- image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1903-amd64
platform:
architecture: amd64
os: windows
version: 1903
- image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: windows os: windows
version: 1809 version: 1809
-
image: plugins/ecr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-ltsc2022-amd64
platform:
architecture: amd64
os: windows
version: ltsc2022
-4
View File
@@ -1,4 +0,0 @@
FROM plugins/docker:linux-amd64
ADD release/linux/amd64/drone-gar /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-gar"]
-4
View File
@@ -1,4 +0,0 @@
FROM plugins/docker:linux-arm64
ADD release/linux/arm64/drone-gar /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-gar"]
-10
View File
@@ -1,10 +0,0 @@
# escape=`
FROM plugins/docker:windows-1809-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone GAR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-gar.exe C:/bin/drone-gar.exe
ENTRYPOINT [ "C:\\bin\\drone-gar.exe" ]
@@ -1,10 +0,0 @@
# escape=`
FROM plugins/docker:windows-ltsc2022-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone GAR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-gar.exe C:/bin/drone-gar.exe
ENTRYPOINT [ "C:\\bin\\drone-gar.exe" ]
-31
View File
@@ -1,31 +0,0 @@
image: plugins/gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: plugins/gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: plugins/gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8
-
image: plugins/gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64
platform:
architecture: amd64
os: windows
version: 1809
-
image: plugins/gar:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-ltsc2022-amd64
platform:
architecture: amd64
os: windows
version: ltsc2022
+4
View File
@@ -0,0 +1,4 @@
FROM plugins/docker:linux-arm
ADD release/linux/arm/drone-gcr /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-gcr"]
@@ -1,5 +1,5 @@
# escape=` # escape=`
FROM plugins/docker:windows-ltsc2022-amd64 FROM plugins/docker:windows-1903-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" ` LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone GCR" ` org.label-schema.name="Drone GCR" `
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-1909-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone GCR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-gcr.exe C:/bin/drone-gcr.exe
ENTRYPOINT [ "C:\\bin\\drone-gcr.exe" ]
+10
View File
@@ -0,0 +1,10 @@
# escape=`
FROM plugins/docker:windows-2004-amd64
LABEL maintainer="Drone.IO Community <drone-dev@googlegroups.com>" `
org.label-schema.name="Drone GCR" `
org.label-schema.vendor="Drone.IO Community" `
org.label-schema.schema-version="1.0"
ADD release/windows/amd64/drone-gcr.exe C:/bin/drone-gcr.exe
ENTRYPOINT [ "C:\\bin\\drone-gcr.exe" ]
+25 -12
View File
@@ -1,31 +1,44 @@
image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}} {{#if build.tags}}
tags: tags:
{{#each build.tags}} {{#each build.tags}}
- {{this}} - {{this}}
{{/each}} {{/each}}
{{/if}} {{/if}}
manifests: manifests:
- - image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- - image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform: platform:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
- - image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64 platform:
architecture: arm
os: linux
variant: v7
- image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-2004-amd64
platform:
architecture: amd64
os: windows
version: 2004
- image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1909-amd64
platform:
architecture: amd64
os: windows
version: 1909
- image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1903-amd64
platform:
architecture: amd64
os: windows
version: 1903
- image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-1809-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: windows os: windows
version: 1809 version: 1809
-
image: plugins/gcr:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}windows-ltsc2022-amd64
platform:
architecture: amd64
os: windows
version: ltsc2022
+4
View File
@@ -0,0 +1,4 @@
FROM plugins/docker:linux-arm
ADD release/linux/arm/drone-heroku /bin/
ENTRYPOINT ["/usr/local/bin/dockerd-entrypoint.sh", "/bin/drone-heroku"]
+9 -4
View File
@@ -1,19 +1,24 @@
image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}} image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}} {{#if build.tags}}
tags: tags:
{{#each build.tags}} {{#each build.tags}}
- {{this}} - {{this}}
{{/each}} {{/each}}
{{/if}} {{/if}}
manifests: manifests:
- - image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform: platform:
architecture: amd64 architecture: amd64
os: linux os: linux
- - image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform: platform:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
- image: plugins/heroku:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
platform:
architecture: arm
os: linux
variant: v7
-180
View File
@@ -1,181 +1 @@
package docker package docker
import (
"os/exec"
"reflect"
"strings"
"testing"
"github.com/dchest/uniuri"
)
func TestCommandBuild(t *testing.T) {
tempTag := strings.ToLower(uniuri.New())
tcs := []struct {
name string
build Build
want *exec.Cmd
}{
{
name: "secret from env var",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=FOO_SECRET_ENV_VAR",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
"--secret id=foo_secret,env=FOO_SECRET_ENV_VAR",
),
},
{
name: "secret from file",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
SecretFiles: []string{
"foo_secret=/path/to/foo_secret",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
"--secret id=foo_secret,src=/path/to/foo_secret",
),
},
{
name: "multiple mixed secrets",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=FOO_SECRET_ENV_VAR",
"bar_secret=BAR_SECRET_ENV_VAR",
},
SecretFiles: []string{
"foo_secret=/path/to/foo_secret",
"bar_secret=/path/to/bar_secret",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
"--secret id=foo_secret,env=FOO_SECRET_ENV_VAR",
"--secret id=bar_secret,env=BAR_SECRET_ENV_VAR",
"--secret id=foo_secret,src=/path/to/foo_secret",
"--secret id=bar_secret,src=/path/to/bar_secret",
),
},
{
name: "invalid mixed secrets",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
SecretEnvs: []string{
"foo_secret=",
"=FOO_SECRET_ENV_VAR",
"",
},
SecretFiles: []string{
"foo_secret=",
"=/path/to/bar_secret",
"",
},
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
),
},
{
name: "platform argument",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
Platform: "test/platform",
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
"--platform",
"test/platform",
),
},
{
name: "ssh agent",
build: Build{
Name: "plugins/drone-docker:latest",
TempTag: tempTag,
Dockerfile: "Dockerfile",
Context: ".",
SSHKeyPath: "id_rsa=/root/.ssh/id_rsa",
},
want: exec.Command(
dockerExe,
"build",
"--rm=true",
"-f",
"Dockerfile",
"-t",
tempTag,
".",
"--ssh id_rsa=/root/.ssh/id_rsa",
),
},
}
for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
cmd := commandBuild(tc.build)
if !reflect.DeepEqual(cmd.String(), tc.want.String()) {
t.Errorf("Got cmd %v, want %v", cmd, tc.want)
}
})
}
}
-41
View File
@@ -1,41 +0,0 @@
{
"Id": "sha256:3b0709c9afb41629c79c93355feed114d08a8c1bedd975eb53af08f4b867fd91",
"RepoTags": [
"798a0dae10d63d281eff4c06eaa12001ffd23740:latest",
"tphoney/test:latest"
],
"ParsedRepoTags": [
{
"Tag": ""
},
{
"Tag": ""
},
{
"Tag": "798a0dae10d63d281eff4c06eaa12001ffd23740:latest"
},
{
"Tag": "tphoney/test:latest"
}
],
"RepoDigests": [
"tphoney/test@sha256:93f8b95aaae7d194208b72e94a3a90544b00c8f2ad45aeb89d81a0c6ccbc5e19"
],
"Parent": "sha256:493aa330a5929027dd8ecded9fa8c473a1508d17c0fd7d6a94a7f197f8d22c60",
"Comment": "",
"Created": "2022-02-16T11:13:40.8956582Z",
"Container": "a57c0ca4dd2e081df8758e00549f7abe83803f1a1a7aaaf1cd8e685a5eb5a097",
"DockerVersion": "20.10.9",
"Author": "",
"Architecture": "amd64",
"Os": "linux",
"Size": 14045949,
"VirtualSize": 14045949,
"Metadata": {
"LastTagTime": "2022-02-16T11:13:40.9433973Z"
},
"SizeString": "13.40MB",
"VirtualSizeString": "13.40MB",
"Time": "2022-02-16T11:13:40Z",
"URL": "http://hub.docker.com/repositories/tphoney/test/"
}
-138
View File
@@ -1,138 +0,0 @@
{
"type": "AdaptiveCard",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "Image",
"url": "https://d36jcksde1wxzq.cloudfront.net/be7833db9bddb4494d2a7c3dd659199a.png",
"size": "small"
}
],
"width": "auto"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"text": "Plugin: Drone Docker",
"wrap": true,
"size": "Small",
"weight": "Bolder",
"isSubtle": false,
"spacing": "Small"
},
{
"type": "TextBlock",
"text": "DIGEST: ${RepoDigests[0]}",
"wrap": true,
"size": "Small",
"weight": "Lighter",
"isSubtle": true,
"spacing": "Small"
}
],
"width": "stretch"
}
],
"style": "default"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"weight": "Lighter",
"text": "TAGS",
"wrap": true,
"size": "Small",
"isSubtle": true,
"spacing": "Medium"
},
{
"type": "FactSet",
"facts": [
{
"title": "${Tag}",
"value": ""
}
],
"spacing": "Small",
"$data": "${ParsedRepoTags}",
"wrap": true,
"size": "Small",
"weight": "Bolder"
}
],
"separator": true,
"width": "auto"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"weight": "Lighter",
"text": "SIZE",
"wrap": true,
"size": "Small",
"isSubtle": true
},
{
"type": "TextBlock",
"spacing": "Small",
"text": "${SizeString}",
"wrap": true,
"weight": "Bolder"
}
],
"width": "auto",
"separator": true,
"spacing": "Medium"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"weight": "Lighter",
"text": "LAST PUSHED",
"wrap": true,
"size": "Small",
"isSubtle": true
},
{
"type": "TextBlock",
"spacing": "Small",
"text": "{{DATE(${Time})}} - {{TIME(${Time})}}",
"wrap": true,
"weight": "Bolder"
}
],
"width": "auto",
"separator": true,
"spacing": "Medium"
}
],
"style": "default",
"separator": true
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "Go to image",
"url": "${url}"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
View File
View File
-8
View File
@@ -1,8 +0,0 @@
This document explains on how to install certain git hooks globally for all repositories in your machine.
Step 1: git clone https://github.com/drone-plugins/drone-docker.git
Step 2: cd git-hooks
Step 3: Run install.sh
"install.sh" script will create .git_template in the user directory and will put the git hook and its dependent scripts in it. Along with the .git_template folder, it will add 2 sections "init" and "hooks boolean" in the .gitconfig file in the same user's root directory.
After running "install.sh" if you create/clone a new git repository then all the hooks will get install automatically for the git repository. In case of existing git repository copy the contents of ~/.git_template/hooks into the .git/hooks directory of existing git repository.
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
#Helper script to be used as a pre-commit hook.
echo "This hook checks for any secrets getting pushed as part of commit. If you feel that scan is false positive. \
Then add the exclusion in .gitleaksignore file. For more info visit: https://github.com/zricethezav/gitleaks"
GIT_LEAKS_PRE_COMMIT=s$(git config --bool hook.pre-commit.gitleak)
echo "INFO: Scanning Commits information for any GIT LEAKS"
gitleaks protect --staged -v --exit-code=100
STATUS=$?
if [ $STATUS = 100 ]; then
echo "WARNING: GIT LEAKS has detected sensitive information in your changes. Please remove them or add them (IF NON-SENSITIVE) in .gitleaksignore file."
else
exit 0
fi
-18
View File
@@ -1,18 +0,0 @@
#!/bin/bash
#Helper script to be used as a pre-commit hook.
echo "This hook checks for any secrets getting pushed as part of commit. If you feel that scan is false positive. \
Then add the exclusion in .gitleaksignore file. For more info visit: https://github.com/zricethezav/gitleaks"
GIT_LEAKS=$(git config --bool hook.pre-push.gitleaks)
echo "INFO: Scanning Commits information for any GIT LEAKS"
gitleaks detect -s ./ --log-level=debug --log-opts=-1 -v
STATUS=$?
if [ $STATUS != 0 ]; then
echo "WARNING: GIT LEAKS has detected sensitive information in your changes. Please remove them or add them (IF NON-SENSITIVE) in .gitleaksignore file."
exit $STATUS
else
exit 0
fi
-24
View File
@@ -1,24 +0,0 @@
#!/usr/bin/env bash
GL_SCRIPT_PATH="$HOME/.git_template/hooks/git-leaks-pre-commit.sh"
pushd `dirname $0` > /dev/null && cd ../.. && BASEDIR=$(pwd -L) && popd > /dev/null
BASENAME=`basename $0`
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
#Initial commit : diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
GIT_LEAKS_PRE_COMMIT=hook.pre-commit.gitleaks
if [ "`git config $GIT_LEAKS_PRE_COMMIT`" == "false" ]
then
echo -e '\033[0;31m' checking git leaks is disabled - to enable: '\033[0;37m'git config --unset $GIT_LEAKS_PRE_COMMIT '\033[0m'
echo -e '\033[0;34m' checking git leaks ... to enable: '\033[0;37m'git config --add $GIT_LEAKS_PRE_COMMIT true '\033[0m'
else
echo -e '\033[0;34m' checking for git leaks...
[ -f "${GL_SCRIPT_PATH}" ] && . ${GL_SCRIPT_PATH} || echo "ERROR: Hook Script Not Found..." && exit 404
fi
-24
View File
@@ -1,24 +0,0 @@
#!/usr/bin/env bash
GL_SCRIPT_PATH="$HOME/.git_template/hooks/git-leaks.sh"
pushd `dirname $0` > /dev/null && cd ../.. && BASEDIR=$(pwd -L) && popd > /dev/null
BASENAME=`basename $0`
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
#Initial commit : diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
GIT_LEAKS=hook.pre-push.gitleaks
if [ "`git config $GIT_LEAKS`" == "false" ]
then
echo -e '\033[0;31m' checking git leaks is disabled - to enable: '\033[0;37m'git config --unset $GIT_LEAKS '\033[0m'
echo -e '\033[0;34m' checking git leaks ... to enable: '\033[0;37m'git config --add $GIT_LEAKS true '\033[0m'
else
echo -e '\033[0;34m' checking for git leaks...
[ -f "${GL_SCRIPT_PATH}" ] && . ${GL_SCRIPT_PATH} || echo "ERROR: Hook Script Not Found..." && exit 404
fi
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
#Function to check if package is installed or not
#args: $1: Name of the Package
function check_package_installed() {
LOCAL_PACKAGE_NAME=$1
echo "Checking if $LOCAL_PACKAGE_NAME is installed or not..."
brew list $LOCAL_PACKAGE_NAME
if [ "$?" -eq 1 ];then
echo "Installing $LOCAL_PACKAGE_NAME package..."
brew install $LOCAL_PACKAGE_NAME
fi
}
function create_git_template() {
cd $BASEDIR
mkdir -p ~/.git_template/hooks
git config --global init.templatedir ${GIT_TEMPLATE}
git config --global --add $GIT_LEAKS true
git config --global --add $GIT_LEAKS_PRE_COMMIT true
find hooks/ -type f -exec cp "{}" ~/.git_template/hooks \;
#cp -f hooks/* ~/.git_template/hooks
cat ~/.gitconfig
}
GIT_TEMPLATE="~/.git_template"
GIT_LEAKS=hook.pre-push.gitleaks
GIT_LEAKS_PRE_COMMIT=hook.pre-commit.gitleaks
pushd `dirname $0` && BASEDIR=$(pwd -L) && popd
echo This script will install hooks that run scripts that could be updated without notice.
while true; do
read -p "Do you wish to install these hooks?" yn
case $yn in
[Yy]* ) check_package_installed "gitleaks";
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
create_git_template
+5 -45
View File
@@ -1,53 +1,13 @@
module github.com/drone-plugins/drone-docker module github.com/drone-plugins/drone-docker
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
github.com/aws/aws-sdk-go v1.26.7 github.com/aws/aws-sdk-go v1.26.7
github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver v0.2.0
github.com/dchest/uniuri v1.2.0
github.com/drone-plugins/drone-plugin-lib v0.4.1
github.com/drone/drone-go v1.7.1
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.3.0
github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.3.0
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.10.0
github.com/urfave/cli v1.22.2 github.com/urfave/cli v1.22.2
golang.org/x/oauth2 v0.27.0 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e // indirect
google.golang.org/api v0.146.0 golang.org/x/text v0.3.0 // indirect
) )
require ( go 1.13
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
go 1.23.0
toolchain go1.23.7
+23 -192
View File
@@ -1,211 +1,42 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aws/aws-sdk-go v1.26.7 h1:ObjEnmzvSdYy8KVd3me7v/UMyCn81inLy2SyoIPoBkg= github.com/aws/aws-sdk-go v1.26.7 h1:ObjEnmzvSdYy8KVd3me7v/UMyCn81inLy2SyoIPoBkg=
github.com/aws/aws-sdk-go v1.26.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.26.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/drone-plugins/drone-plugin-lib v0.4.1 h1:47rZlmcMpr1hSp+6Gl+1Z4t+efi/gMQU3lxukC1Yg64=
github.com/drone-plugins/drone-plugin-lib v0.4.1/go.mod h1:KwCu92jFjHV3xv2hu5Qg/8zBNvGwbhoJDQw/EwnTvoM=
github.com/drone/drone-go v1.7.1 h1:ZX+3Rs8YHUSUQ5mkuMLmm1zr1ttiiE2YGNxF3AnyDKw=
github.com/drone/drone-go v1.7.1/go.mod h1:fxCf9jAnXDZV1yDr0ckTuWd1intvcQwfJmTRpTZ1mXg=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743 h1:X3Xxno5Ji8idrNiUoFc7QyXpqhSYlDRYQmc7mlpMBzU=
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743/go.mod h1:KrtyD5PFj++GKkFS/7/RRrfnRhAMGQwy75GLCHWrCNs=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.146.0 h1:9aBYT4vQXt9dhCuLNfwfd3zpwu8atg0yPkjBymwSrOM=
google.golang.org/api v0.146.0/go.mod h1:OARJqIfoYjXJj4C1AiBSXYZt03qsoz8FQYU6fBEfrHM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8=
google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-75
View File
@@ -1,75 +0,0 @@
package azure
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
const DefaultResource = "https://management.azure.com/"
const defaultAuthorityHost = "https://login.microsoftonline.com"
const defaultHTTPTimeout = 30 * time.Second
// GetAADAccessTokenViaClientAssertion exchanges an external OIDC ID token for an Azure AD access token
func GetAADAccessTokenViaClientAssertion(ctx context.Context, tenantID, clientID, oidcToken, authorityHost string) (string, error) {
resource := DefaultResource
form := url.Values{
"client_id": {clientID},
"scope": {resource + ".default"},
"grant_type": {"client_credentials"},
"client_assertion_type": {"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
"client_assertion": {oidcToken},
}
base := authorityHost
if strings.TrimSpace(base) == "" {
base = defaultAuthorityHost
}
base = strings.TrimRight(base, "/")
endpoint := fmt.Sprintf("%s/%s/oauth2/v2.0/token", base, tenantID)
client := &http.Client{Timeout: defaultHTTPTimeout}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, strings.NewReader(form.Encode()))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
var aadErr struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description"`
}
limited := io.LimitedReader{R: resp.Body, N: 4096}
_ = json.NewDecoder(&limited).Decode(&aadErr)
if aadErr.Error != "" {
return "", fmt.Errorf("AAD token request failed: status=%d, error=%s", resp.StatusCode, aadErr.Error)
}
return "", fmt.Errorf("AAD token request failed: status=%d", resp.StatusCode)
}
var payload struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
}
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return "", err
}
if payload.AccessToken == "" {
return "", fmt.Errorf("AAD token response missing access_token")
}
return payload.AccessToken, nil
}
-104
View File
@@ -1,104 +0,0 @@
package azure
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestGetAADAccessTokenViaClientAssertion_Success(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Fatalf("expected POST, got %s", r.Method)
}
if ct := r.Header.Get("Content-Type"); !strings.Contains(ct, "application/x-www-form-urlencoded") {
t.Fatalf("expected form content-type, got %s", ct)
}
if err := r.ParseForm(); err != nil {
t.Fatalf("failed parsing form: %v", err)
}
assertEq(t, r.Form.Get("client_id"), "client")
assertEq(t, r.Form.Get("grant_type"), "client_credentials")
assertEq(t, r.Form.Get("client_assertion_type"), "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
assertEq(t, r.Form.Get("client_assertion"), "idtoken")
assertEq(t, r.Form.Get("scope"), DefaultResource+".default")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"access_token":"AT","token_type":"Bearer","expires_in":3600}`))
}))
defer ts.Close()
tok, err := GetAADAccessTokenViaClientAssertion(context.Background(), "tenant", "client", "idtoken", ts.URL)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tok != "AT" {
t.Fatalf("expected access token AT, got %q", tok)
}
}
func TestGetAADAccessTokenViaClientAssertion_400WithErrorField(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(`{"error":"invalid_client","error_description":"bad"}`))
}))
defer ts.Close()
_, err := GetAADAccessTokenViaClientAssertion(context.Background(), "tenant", "client", "idtoken", ts.URL)
if err == nil || !strings.Contains(err.Error(), "status=400") || !strings.Contains(err.Error(), "invalid_client") {
t.Fatalf("expected 400 with invalid_client error, got %v", err)
}
}
func TestGetAADAccessTokenViaClientAssertion_400WithoutErrorField(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("{}"))
}))
defer ts.Close()
_, err := GetAADAccessTokenViaClientAssertion(context.Background(), "tenant", "client", "idtoken", ts.URL)
if err == nil || !strings.Contains(err.Error(), "status=400") {
t.Fatalf("expected 400 error, got %v", err)
}
}
func TestGetAADAccessTokenViaClientAssertion_MalformedJSON(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("not-json"))
}))
defer ts.Close()
_, err := GetAADAccessTokenViaClientAssertion(context.Background(), "tenant", "client", "idtoken", ts.URL)
if err == nil {
t.Fatalf("expected JSON decode error, got nil")
}
}
func TestGetAADAccessTokenViaClientAssertion_MissingAccessToken(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"token_type":"Bearer","expires_in":3600}`))
}))
defer ts.Close()
_, err := GetAADAccessTokenViaClientAssertion(context.Background(), "tenant", "client", "idtoken", ts.URL)
if err == nil || !strings.Contains(err.Error(), "missing access_token") {
t.Fatalf("expected missing access_token error, got %v", err)
}
}
func assertEq(t *testing.T, got, want string) {
t.Helper()
if got != want {
t.Fatalf("mismatch: got=%q want=%q", got, want)
}
}
-70
View File
@@ -1,70 +0,0 @@
package docker
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
)
const (
v2HubRegistryURL string = "https://registry.hub.docker.com/v2/"
v1RegistryURL string = "https://index.docker.io/v1/" // Default registry
v2RegistryURL string = "https://index.docker.io/v2/" // v2 registry is not supported
)
type (
Auth struct {
Auth string `json:"auth"`
}
Config struct {
Auths map[string]Auth `json:"auths"`
CredHelpers map[string]string `json:"credHelpers,omitempty"`
}
)
type RegistryCredentials struct {
Registry string
Username string
Password string
}
func NewConfig() *Config {
return &Config{
Auths: make(map[string]Auth),
CredHelpers: make(map[string]string),
}
}
func (c *Config) SetAuth(registry, username, password string) {
authBytes := []byte(username + ":" + password)
encodedString := base64.StdEncoding.EncodeToString(authBytes)
c.Auths[registry] = Auth{Auth: encodedString}
}
func (c *Config) SetCredHelper(registry, helper string) {
c.CredHelpers[registry] = helper
}
func (c *Config) CreateDockerConfigJson(credentials []RegistryCredentials) ([]byte, error) {
for _, cred := range credentials {
if cred.Registry != "" {
if cred.Username == "" {
return nil, fmt.Errorf("Username must be specified for registry: %s", cred.Registry)
}
if cred.Password == "" {
return nil, fmt.Errorf("Password must be specified for registry: %s", cred.Registry)
}
c.SetAuth(cred.Registry, cred.Username, cred.Password)
}
}
jsonBytes, err := json.Marshal(c)
if err != nil {
return nil, errors.New("failed to serialize docker config json")
}
return jsonBytes, nil
}
-64
View File
@@ -1,64 +0,0 @@
package docker
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
const (
RegistryV1 string = "https://index.docker.io/v1/"
RegistryV2 string = "https://index.docker.io/v2/"
RegistryECRPublic string = "public.ecr.aws"
)
func TestConfig(t *testing.T) {
c := NewConfig()
assert.NotNil(t, c.Auths)
assert.NotNil(t, c.CredHelpers)
c.SetAuth(RegistryV1, "test", "password")
expectedAuth := Auth{Auth: "dGVzdDpwYXNzd29yZA=="}
assert.Equal(t, expectedAuth, c.Auths[RegistryV1])
c.SetCredHelper(RegistryECRPublic, "ecr-login")
assert.Equal(t, "ecr-login", c.CredHelpers[RegistryECRPublic])
tempDir, err := ioutil.TempDir("", "docker-config-test")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)
credentials := []RegistryCredentials{
{
Registry: "https://index.docker.io/v1/",
Username: "user1",
Password: "pass1",
},
{
Registry: "gcr.io",
Username: "user2",
Password: "pass2",
},
}
jsonBytes, err := c.CreateDockerConfigJson(credentials)
assert.NoError(t, err)
configPath := filepath.Join(tempDir, "config.json")
err = ioutil.WriteFile(configPath, jsonBytes, 0644)
assert.NoError(t, err)
data, err := ioutil.ReadFile(configPath)
assert.NoError(t, err)
var configFromFile Config
err = json.Unmarshal(data, &configFromFile)
assert.NoError(t, err)
assert.Equal(t, c.Auths, configFromFile.Auths)
assert.Equal(t, c.CredHelpers, configFromFile.CredHelpers)
}
-65
View File
@@ -1,65 +0,0 @@
package gcp
import (
"context"
"fmt"
"golang.org/x/oauth2"
"google.golang.org/api/iamcredentials/v1"
"google.golang.org/api/option"
"google.golang.org/api/sts/v1"
)
type staticTokenSource struct {
token *oauth2.Token
}
func (s *staticTokenSource) Token() (*oauth2.Token, error) {
return s.token, nil
}
func GetFederalToken(idToken, projectNumber, poolId, providerId string) (string, error) {
ctx := context.Background()
stsService, err := sts.NewService(ctx, option.WithoutAuthentication())
if err != nil {
return "", err
}
audience := fmt.Sprintf("//iam.googleapis.com/projects/%s/locations/global/workloadIdentityPools/%s/providers/%s", projectNumber, poolId, providerId)
tokenRequest := &sts.GoogleIdentityStsV1ExchangeTokenRequest{
GrantType: "urn:ietf:params:oauth:grant-type:token-exchange",
SubjectToken: idToken,
Audience: audience,
Scope: "https://www.googleapis.com/auth/cloud-platform",
RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
SubjectTokenType: "urn:ietf:params:oauth:token-type:id_token",
}
tokenResponse, err := stsService.V1.Token(tokenRequest).Do()
if err != nil {
return "", err
}
return tokenResponse.AccessToken, nil
}
func GetGoogleCloudAccessToken(federatedToken string, serviceAccountEmail string) (string, error) {
ctx := context.Background()
tokenSource := &staticTokenSource{
token: &oauth2.Token{AccessToken: federatedToken},
}
service, err := iamcredentials.NewService(ctx, option.WithTokenSource(tokenSource))
if err != nil {
return "", err
}
name := "projects/-/serviceAccounts/" + serviceAccountEmail
rb := &iamcredentials.GenerateAccessTokenRequest{
Scope: []string{"https://www.googleapis.com/auth/cloud-platform"},
}
resp, err := service.Projects.ServiceAccounts.GenerateAccessToken(name, rb).Do()
if err != nil {
return "", err
}
return resp.AccessToken, nil
}
+206
View File
@@ -0,0 +1,206 @@
local windows_pipe = '\\\\\\\\.\\\\pipe\\\\docker_engine';
local windows_pipe_volume = 'docker_pipe';
local test_pipeline_name = 'testing';
local windows(os) = os == 'windows';
local golang_image(os, version) =
'golang:' + '1.11' + if windows(os) then '-windowsservercore-' + version else '';
{
test(os='linux', arch='amd64', version='')::
local is_windows = windows(os);
local golang = golang_image(os, version);
local volumes = if is_windows then [{name: 'gopath', path: 'C:\\\\gopath'}] else [{name: 'gopath', path: '/go',}];
{
kind: 'pipeline',
name: test_pipeline_name,
platform: {
os: os,
arch: arch,
version: if std.length(version) > 0 then version,
},
steps: [
{
name: 'vet',
image: golang,
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'go vet ./...',
],
volumes: volumes,
},
{
name: 'test',
image: golang,
pull: 'always',
environment: {
GO111MODULE: 'on',
},
commands: [
'go test -cover ./...',
],
volumes: volumes,
},
],
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
'refs/pull/**',
],
},
volumes: [{name: 'gopath', temp: {}}]
},
build(name, os='linux', arch='amd64', version='')::
local is_windows = windows(os);
local tag = if is_windows then os + '-' + version else os + '-' + arch;
local file_suffix = std.strReplace(tag, '-', '.');
local volumes = if is_windows then [{ name: windows_pipe_volume, path: windows_pipe }] else [];
local golang = golang_image(os, version);
local plugin_repo = 'plugins/' + name;
local extension = if is_windows then '.exe' else '';
local depends_on = if name == 'docker' then [test_pipeline_name] else [tag + '-docker'];
{
kind: 'pipeline',
name: tag + '-' + name,
platform: {
os: os,
arch: arch,
version: if std.length(version) > 0 then version,
},
steps: [
{
name: 'build-push',
image: golang,
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags "-X main.version=${DRONE_COMMIT_SHA:0:8}" -a -tags netgo -o release/' + os + '/' + arch + '/drone-' + name + extension + ' ./cmd/drone-' + name,
],
when: {
event: {
exclude: ['tag'],
},
},
},
{
name: 'build-tag',
image: golang,
pull: 'always',
environment: {
CGO_ENABLED: '0',
GO111MODULE: 'on',
},
commands: [
'go build -v -ldflags "-X main.version=${DRONE_TAG##v}" -a -tags netgo -o release/' + os + '/' + arch + '/drone-' + name + extension + ' ./cmd/drone-' + name,
],
when: {
event: ['tag'],
},
},
if name == "docker" then {
name: 'executable',
image: golang,
pull: 'always',
commands: [
'./release/' + os + '/' + arch + '/drone-' + name + extension + ' --help',
],
},
{
name: 'dryrun',
image: 'plugins/docker:' + tag,
pull: 'always',
settings: {
dry_run: true,
tags: tag,
dockerfile: 'docker/'+ name +'/Dockerfile.' + file_suffix,
daemon_off: if is_windows then 'true' else 'false',
repo: plugin_repo,
username: { from_secret: 'docker_username' },
password: { from_secret: 'docker_password' },
},
volumes: if std.length(volumes) > 0 then volumes,
when: {
event: ['pull_request'],
},
},
{
name: 'publish',
image: 'plugins/docker:' + tag,
pull: 'always',
settings: {
auto_tag: true,
auto_tag_suffix: tag,
daemon_off: if is_windows then 'true' else 'false',
dockerfile: 'docker/' + name + '/Dockerfile.' + file_suffix,
repo: plugin_repo,
username: { from_secret: 'docker_username' },
password: { from_secret: 'docker_password' },
},
volumes: if std.length(volumes) > 0 then volumes,
when: {
event: {
exclude: ['pull_request'],
},
},
},
],
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
'refs/pull/**',
],
},
depends_on: depends_on,
volumes: if is_windows then [{ name: windows_pipe_volume, host: { path: windows_pipe } }],
},
notifications(name, os='linux', arch='amd64', version='', depends_on=[])::
{
kind: 'pipeline',
name: 'notifications-' + name,
platform: {
os: os,
arch: arch,
version: if std.length(version) > 0 then version,
},
steps: [
{
name: 'manifest',
image: 'plugins/manifest',
pull: 'always',
settings: {
username: { from_secret: 'docker_username' },
password: { from_secret: 'docker_password' },
spec: 'docker/' + name + '/manifest.tmpl',
ignore_missing: true,
auto_tag: true,
},
},
{
name: 'microbadger',
image: 'plugins/webhook',
pull: 'always',
settings: {
urls: { from_secret: 'microbadger_' + name },
},
},
],
depends_on: [x + '-' + name for x in depends_on],
trigger: {
ref: [
'refs/heads/master',
'refs/tags/**',
],
},
},
}
-35
View File
@@ -1,35 +0,0 @@
# this script is used by the continuous integration server to
# build and publish the docker image for a commit to master.
$ErrorActionPreference = "Stop"
$env:GOOS="windows"
$env:GOARCH="amd64"
$env:CGO_ENABLED="0"
if (-not (Test-Path env:VERSION)) {
$env:VERSION="1809"
}
if (-not (Test-Path env:REGISTRY)) {
$env:REGISTRY="docker"
}
echo $env:GOOS
echo $env:GOARCH
echo $env:VERSION
echo $env:REGISTRY
# build the binary
Write-Host "+ go build -o release/windows/amd64/drone-${env:REGISTRY}.exe ./cmd/drone-${env:REGISTRY}";
go build -o release/windows/amd64/drone-${env:REGISTRY}.exe ./cmd/drone-${env:REGISTRY}
# build and publish the docker image
docker login -u ${env:USERNAME} -p ${env:PASSWORD}
Write-Host "+ docker build -f docker/${env:REGISTRY}/Dockerfile.windows.amd64.${env:VERSION} -t plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64 .";
docker build -f docker/${env:REGISTRY}/Dockerfile.windows.amd64.${env:VERSION} -t plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64 .
Write-Host "+ docker push plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64"
docker push plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64
# remove images from local cache
Write-Host "+ docker rmi plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64"
docker rmi plugins/${env:REGISTRY}:windows-${env:VERSION}-amd64
-66
View File
@@ -1,66 +0,0 @@
# this script is used by the continuous integration server to
# build and publish the docker image for a tagged revsision.
$ErrorActionPreference = "Stop"
$env:GOOS="windows"
$env:GOARCH="amd64"
$env:CGO_ENABLED="0"
if (-not (Test-Path env:VERSION)) {
$env:VERSION="1809"
}
if (-not (Test-Path env:DRONE_SEMVER_SHORT)) {
echo "missing semver"
exit 1
}
if (-not (Test-Path env:REGISTRY)) {
$env:REGISTRY="docker"
}
# define the image tags
$env:IMAGE_PATCH="plugins/${env:REGISTRY}:${env:DRONE_SEMVER_SHORT}-windows-${env:VERSION}-amd64"
$env:IMAGE_MAJOR="plugins/${env:REGISTRY}:${env:DRONE_SEMVER_MAJOR}-windows-${env:VERSION}-amd64"
$env:IMAGE_MINOR="plugins/${env:REGISTRY}:${env:DRONE_SEMVER_MAJOR}.${env:DRONE_SEMVER_MINOR}-windows-${env:VERSION}-amd64"
echo "build environment:"
echo $env:GOOS
echo $env:GOARCH
echo $env:VERSION
# build the binary
Write-Host "+ go build -o release/windows/amd64/drone-${env:REGISTRY}.exe ./cmd/drone-${env:REGISTRY}"
go build -o release/windows/amd64/drone-${env:REGISTRY}.exe ./cmd/drone-${env:REGISTRY}
# authenticate with the docker registry
docker login -u ${env:USERNAME} -p ${env:PASSWORD}
echo "building images:"
echo ${env:IMAGE_PATCH}
echo ${env:IMAGE_MINOR}
echo ${env:IMAGE_MAJOR}
# build and tag the docker images
Write-Host "+ docker build -f docker/${env:REGISTRY}/Dockerfile.windows.amd64.${env:VERSION} -t ${env:IMAGE_PATCH} ."
docker build -f docker/${env:REGISTRY}/Dockerfile.windows.amd64.${env:VERSION} -t ${env:IMAGE_PATCH} .
Write-Host "+ docker tag ${env:IMAGE_PATCH} ${env:IMAGE_MAJOR}"
docker tag ${env:IMAGE_PATCH} ${env:IMAGE_MAJOR}
Write-Host "+ docker tag ${env:IMAGE_PATCH} ${env:IMAGE_MINOR}"
docker tag ${env:IMAGE_PATCH} ${env:IMAGE_MINOR}
# publish the docker images
Write-Host "+ docker push ${env:IMAGE_MAJOR}"
docker push ${env:IMAGE_MAJOR}
Write-Host "+ docker push ${env:IMAGE_MINOR}"
docker push ${env:IMAGE_MINOR}
Write-Host "+ docker push ${env:IMAGE_PATCH}"
docker push ${env:IMAGE_PATCH}
# remove images after from local cache
Write-Host "+ docker rmi ${env:IMAGE_MAJOR}"
docker rmi ${env:IMAGE_MAJOR}
Write-Host "+ docker rmi ${env:IMAGE_MINOR}"
docker rmi ${env:IMAGE_MINOR}
Write-Host "+ docker rmi ${env:IMAGE_PATCH}"
docker rmi ${env:IMAGE_PATCH}