Skip to content

Instantly share code, notes, and snippets.

@s1moe2
Created February 9, 2021 16:51
Show Gist options
  • Save s1moe2/75343cae5df718e08629f8c65c6ad081 to your computer and use it in GitHub Desktop.
Save s1moe2/75343cae5df718e08629f8c65c6ad081 to your computer and use it in GitHub Desktop.
Find commit hash tag by "latest" tag on same image
package main
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"net/http"
"os"
"time"
)
const dockerAPI = "https://hub.docker.com/v2"
type Tag struct {
Images []struct{
Digest string
}
Name string
}
type Tags struct {
Next string
Results []Tag
}
// This script's goal is to find the commit hash
// corresponding to a docker image tagged with a "latest" Tag.
// A "latest" image is supposed to be tagged with 2 tags: commit hash & latest.
// The only way to find the commit hash tag is by:
// - find image tagged as "latest"
// - get image digest
// - iterate repositories images to find one with a tag != "latest" & digest same as found
func main() {
var dockerUser = flag.String("u", "", "Docker Hub username")
var dockerPassword = flag.String("p", "", "Docker Hub password")
var repository = flag.String("r", "", "Docker repository")
var branch = flag.String("t", "", "Docker Image Tag")
flag.Parse()
token, err := dockerLogin(*dockerUser, *dockerPassword)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
hash, err := findHashTag(token, *dockerUser, *repository, *branch)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(hash)
}
func dockerLogin(user string, password string) (string, error) {
postBody, _ := json.Marshal(map[string]string{
"username": user,
"password": password,
})
responseBody := bytes.NewBuffer(postBody)
url := fmt.Sprintf("%s/users/login", dockerAPI)
resp, err := http.Post(url, "application/json", responseBody)
if err != nil {
return "", err
}
defer resp.Body.Close()
type loginRes struct {
Token string
}
res := &loginRes{}
decoder := json.NewDecoder(resp.Body)
if err = decoder.Decode(&res); err != nil {
return "", err
}
return res.Token, nil
}
func findHashTag(token string, user string, repository string, tag string) (string, error) {
URL := fmt.Sprintf("%s/repositories/%s/%s/tags?n=500", dockerAPI, user, repository)
req, err := http.NewRequest(http.MethodGet, URL, nil)
if err != nil {
return "", err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("JWT %s", token))
client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
tags := &Tags{}
decoder := json.NewDecoder(resp.Body)
if err = decoder.Decode(&tags); err != nil {
return "", err
}
var digest string
for _, t := range tags.Results {
if t.Name == tag {
if len(t.Images) != 1 {
return "", errors.New("found Tag but has no images")
}
digest = t.Images[0].Digest
break
}
}
if len(digest) == 0 {
return "", errors.New("could not find tag digest")
}
var hashTag string
for _, t := range tags.Results {
if t.Name == tag {
continue
}
if len(t.Images) != 1 {
return "", errors.New("found Tag but has no images")
}
if t.Images[0].Digest == digest {
hashTag = t.Name
break
}
}
if len(hashTag) == 0 {
return "", errors.New("could not find hash tag")
}
return hashTag, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment