mirror of
https://github.com/docker/docker-credential-helpers.git
synced 2026-06-28 15:21:29 +05:30
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b9df3ebb5 | |||
| dc10c50685 | |||
| 896eb37d47 | |||
| a14669f4ff | |||
| 74840b3740 | |||
| d3ef442f59 | |||
| f64d6b131b | |||
| 1bb9aa3210 | |||
| 73b9e5d51f | |||
| 0c43fede6d | |||
| a941c5247f | |||
| 097f945536 | |||
| 9272dcb90a | |||
| ecacf8cdcf | |||
| 5be670a285 | |||
| 73aa8c0daa | |||
| c23afb6c37 | |||
| d622133060 | |||
| 12500fb753 | |||
| bf726a0656 | |||
| d9632f6a08 |
@@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
Please make sure you've read and understood our contributing guidelines;
|
||||||
|
https://github.com/docker/cli/blob/master/CONTRIBUTING.md
|
||||||
|
|
||||||
|
** Make sure all your commits include a signature generated with `git commit -s` **
|
||||||
|
|
||||||
|
For additional information on our contributing process, read our contributing
|
||||||
|
guide https://docs.docker.com/opensource/code/
|
||||||
|
|
||||||
|
If this is a bug fix, make sure your description includes "fixes #xxxx", or
|
||||||
|
"closes #xxxx"
|
||||||
|
|
||||||
|
Please provide the following information:
|
||||||
|
-->
|
||||||
|
|
||||||
|
**- What I did**
|
||||||
|
|
||||||
|
**- How I did it**
|
||||||
|
|
||||||
|
**- How to verify it**
|
||||||
|
|
||||||
|
**- Description for the changelog**
|
||||||
|
<!--
|
||||||
|
Write a short (one line) summary that describes the changes in this
|
||||||
|
pull request for inclusion in the changelog:
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
**- A picture of a cute animal (not mandatory but encouraged)**
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "bot"
|
||||||
+22
-20
@@ -15,7 +15,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DESTDIR: ./bin
|
DESTDIR: ./bin
|
||||||
GO_VERSION: 1.21.6
|
GO_VERSION: 1.21.10
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
validate:
|
validate:
|
||||||
@@ -29,10 +29,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
-
|
-
|
||||||
name: Run
|
name: Run
|
||||||
run: |
|
run: |
|
||||||
@@ -46,18 +46,18 @@ jobs:
|
|||||||
os:
|
os:
|
||||||
- ubuntu-22.04
|
- ubuntu-22.04
|
||||||
- ubuntu-20.04
|
- ubuntu-20.04
|
||||||
- macOS-11
|
- macOS-14
|
||||||
|
- macOS-13
|
||||||
- windows-2022
|
- windows-2022
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
-
|
-
|
||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
cache: true
|
|
||||||
-
|
-
|
||||||
name: Install deps (ubuntu)
|
name: Install deps (ubuntu)
|
||||||
if: startsWith(matrix.os, 'ubuntu-')
|
if: startsWith(matrix.os, 'ubuntu-')
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: GPG conf
|
name: GPG conf
|
||||||
if: ${{ !startsWith(matrix.os, 'windows-') }}
|
if: ${{ !startsWith(matrix.os, 'windows-') }}
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v7
|
||||||
id: gpg
|
id: gpg
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: Import GPG key
|
name: Import GPG key
|
||||||
if: ${{ !startsWith(matrix.os, 'windows-') }}
|
if: ${{ !startsWith(matrix.os, 'windows-') }}
|
||||||
uses: crazy-max/ghaction-import-gpg@v5
|
uses: crazy-max/ghaction-import-gpg@v6
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ steps.gpg.outputs.key }}
|
gpg_private_key: ${{ steps.gpg.outputs.key }}
|
||||||
passphrase: ${{ steps.gpg.outputs.passphrase }}
|
passphrase: ${{ steps.gpg.outputs.passphrase }}
|
||||||
@@ -107,22 +107,23 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
file: ${{ env.DESTDIR }}/coverage.txt
|
file: ${{ env.DESTDIR }}/coverage.txt
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
test-sandboxed:
|
test-sandboxed:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
uses: docker/bake-action@v2
|
uses: docker/bake-action@v4
|
||||||
with:
|
with:
|
||||||
targets: test
|
targets: test
|
||||||
set: |
|
set: |
|
||||||
@@ -130,24 +131,25 @@ jobs:
|
|||||||
*.cache-to=type=gha,scope=test,mode=max
|
*.cache-to=type=gha,scope=test,mode=max
|
||||||
-
|
-
|
||||||
name: Upload coverage
|
name: Upload coverage
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
file: ${{ env.DESTDIR }}//coverage.txt
|
file: ${{ env.DESTDIR }}//coverage.txt
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
-
|
-
|
||||||
name: Set up QEMU
|
name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
-
|
-
|
||||||
name: Build
|
name: Build
|
||||||
run: |
|
run: |
|
||||||
@@ -165,7 +167,7 @@ jobs:
|
|||||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -e text -- {} +
|
find ${{ env.DESTDIR }} -type f -exec file -e ascii -e text -- {} +
|
||||||
-
|
-
|
||||||
name: Upload artifacts
|
name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: docker-credential-helpers
|
name: docker-credential-helpers
|
||||||
path: ${{ env.DESTDIR }}/*
|
path: ${{ env.DESTDIR }}/*
|
||||||
@@ -173,7 +175,7 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: GitHub Release
|
name: GitHub Release
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
|
uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
@@ -185,7 +187,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
-
|
-
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
ARG GO_VERSION=1.21.6
|
ARG GO_VERSION=1.21.10
|
||||||
ARG XX_VERSION=1.2.1
|
ARG XX_VERSION=1.4.0
|
||||||
ARG OSXCROSS_VERSION=11.3-r7-debian
|
ARG OSXCROSS_VERSION=11.3-r7-debian
|
||||||
ARG GOLANGCI_LINT_VERSION=v1.55.2
|
ARG GOLANGCI_LINT_VERSION=v1.55.2
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
ARG GO_VERSION=1.21.6
|
ARG GO_VERSION=1.21.10
|
||||||
ARG DISTRO=ubuntu
|
ARG DISTRO=ubuntu
|
||||||
ARG SUITE=focal
|
ARG SUITE=focal
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
variable "GO_VERSION" {
|
variable "GO_VERSION" {
|
||||||
default = "1.21.6"
|
default = "1.21.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Defines the output folder
|
# Defines the output folder
|
||||||
|
|||||||
+23
-17
@@ -87,8 +87,7 @@ func (p Pass) Add(creds *credentials.Credentials) error {
|
|||||||
return errors.New("missing credentials")
|
return errors.New("missing credentials")
|
||||||
}
|
}
|
||||||
|
|
||||||
encoded := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL))
|
encoded := encodeServerURL(creds.ServerURL)
|
||||||
|
|
||||||
_, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username))
|
_, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -99,7 +98,7 @@ func (p Pass) Delete(serverURL string) error {
|
|||||||
return errors.New("missing server url")
|
return errors.New("missing server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL))
|
encoded := encodeServerURL(serverURL)
|
||||||
_, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded))
|
_, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -142,23 +141,14 @@ func (p Pass) Get(serverURL string) (string, string, error) {
|
|||||||
return "", "", errors.New("missing server url")
|
return "", "", errors.New("missing server url")
|
||||||
}
|
}
|
||||||
|
|
||||||
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL))
|
encoded := encodeServerURL(serverURL)
|
||||||
|
|
||||||
if _, err := os.Stat(path.Join(getPassDir(), PASS_FOLDER, encoded)); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return "", "", credentials.NewErrCredentialsNotFound()
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
usernames, err := listPassDir(encoded)
|
usernames, err := listPassDir(encoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(usernames) < 1 {
|
if len(usernames) < 1 {
|
||||||
return "", "", fmt.Errorf("no usernames for %s", serverURL)
|
return "", "", credentials.NewErrCredentialsNotFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := strings.TrimSuffix(usernames[0].Name(), ".gpg")
|
actual := strings.TrimSuffix(usernames[0].Name(), ".gpg")
|
||||||
@@ -180,7 +170,7 @@ func (p Pass) List() (map[string]string, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
serverURL, err := base64.URLEncoding.DecodeString(server.Name())
|
serverURL, err := decodeServerURL(server.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -191,11 +181,27 @@ func (p Pass) List() (map[string]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(usernames) < 1 {
|
if len(usernames) < 1 {
|
||||||
return nil, fmt.Errorf("no usernames for %s", serverURL)
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
resp[string(serverURL)] = strings.TrimSuffix(usernames[0].Name(), ".gpg")
|
resp[serverURL] = strings.TrimSuffix(usernames[0].Name(), ".gpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodeServerURL returns the serverURL in base64-URL encoding to use
|
||||||
|
// as directory-name in pass storage.
|
||||||
|
func encodeServerURL(serverURL string) string {
|
||||||
|
return base64.URLEncoding.EncodeToString([]byte(serverURL))
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeServerURL decodes base64-URL encoded serverURL. ServerURLs are
|
||||||
|
// used in encoded format for directory-names in pass storage.
|
||||||
|
func decodeServerURL(encodedServerURL string) (string, error) {
|
||||||
|
serverURL, err := base64.URLEncoding.DecodeString(encodedServerURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(serverURL), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
package pass
|
package pass
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -116,6 +118,75 @@ func TestPassHelperList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPassHelperWithEmptyServer verifies that empty directories (servers
|
||||||
|
// without credentials) are ignored, but still returns credentials for other
|
||||||
|
// servers.
|
||||||
|
func TestPassHelperWithEmptyServer(t *testing.T) {
|
||||||
|
helper := Pass{}
|
||||||
|
if err := helper.checkInitialized(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
creds := []*credentials.Credentials{
|
||||||
|
{
|
||||||
|
ServerURL: "https://myreqistry.example.com:2375/v1",
|
||||||
|
Username: "foo",
|
||||||
|
Secret: "isthebestmeshuggahalbum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ServerURL: "https://index.example.com/v1//access-token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
for _, cred := range creds {
|
||||||
|
_ = helper.Delete(cred.ServerURL)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, cred := range creds {
|
||||||
|
if cred.Username != "" {
|
||||||
|
if err := helper.Add(cred); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No credentials; create an empty directory for this server.
|
||||||
|
serverURL := encodeServerURL(cred.ServerURL)
|
||||||
|
p := path.Join(getPassDir(), PASS_FOLDER, serverURL)
|
||||||
|
if err := os.Mkdir(p, 0o755); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
credsList, err := helper.List()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if len(credsList) == 0 {
|
||||||
|
t.Error("expected credentials to be returned, but got none")
|
||||||
|
}
|
||||||
|
for _, cred := range creds {
|
||||||
|
if cred.Username != "" {
|
||||||
|
userName, secret, err := helper.Get(cred.ServerURL)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if userName != cred.Username {
|
||||||
|
t.Errorf("expected username %q, actual: %q", cred.Username, userName)
|
||||||
|
}
|
||||||
|
if secret != cred.Secret {
|
||||||
|
t.Errorf("expected secret %q, actual: %q", cred.Secret, secret)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, _, err := helper.Get(cred.ServerURL)
|
||||||
|
if !credentials.IsErrCredentialsNotFound(err) {
|
||||||
|
t.Errorf("expected credentials not found, actual: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMissingCred(t *testing.T) {
|
func TestMissingCred(t *testing.T) {
|
||||||
helper := Pass{}
|
helper := Pass{}
|
||||||
if _, _, err := helper.Get("garbage"); !credentials.IsErrCredentialsNotFound(err) {
|
if _, _, err := helper.Get("garbage"); !credentials.IsErrCredentialsNotFound(err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user