All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.salesforce.dockerfileimageupdate.storage.GitHubJsonStore Maven / Gradle / Ivy

Go to download

This tool provides a mechanism to make security updates to docker images at scale. The tool searches github for declared docker images and sends pull requests to projects that are not using the desired version of the requested docker image.

There is a newer version: 1.1.26
Show newest version
package com.salesforce.dockerfileimageupdate.storage;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.salesforce.dockerfileimageupdate.utils.Constants;
import com.salesforce.dockerfileimageupdate.utils.DockerfileGitHubUtil;
import com.salesforce.dockerfileimageupdate.utils.GitHubUtil;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.kohsuke.github.GHBlob;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GitHubJsonStore implements ImageTagStore {
    private static final Logger log = LoggerFactory.getLogger(GitHubJsonStore.class);
    private final GitHubUtil gitHubUtil;
    private final String store;

    public GitHubJsonStore(GitHubUtil gitHubUtil, String store) {
        this.gitHubUtil = gitHubUtil;
        this.store = store;
    }

    /* The store link should be a repository name on Github. */
    public void updateStore(String img, String tag) throws IOException {
        if (store == null) {
            log.info("Image tag store cannot be null. Skipping store update...");
            return;
        }
        log.info("Updating store: {} with image: {} tag: {}...", store, img, tag);
        GHRepository storeRepo;
        try {
            GHMyself myself = gitHubUtil.getMyself();
            String ownerOrg = myself.getLogin();
            storeRepo = gitHubUtil.getRepo(Paths.get(ownerOrg, store).toString());
        } catch (IOException e) {
            storeRepo = gitHubUtil.createPublicRepo(store);
        }
        updateStoreOnGithub(storeRepo, Constants.STORE_JSON_FILE, img, tag);
    }

    /**
     * This methods will check if the tag store at path
     * is created or not, if not it will create a new tag store.
     *
     * @param repo {@link GHRepository} git repository object.
     * @param path filename with path with in repo for the tag store.
     * @throws IOException when tag store at path
     *                     can not be created.
     */
    public void initializeTagStoreIfRequired(GHRepository repo, String path) throws IOException {
        try {
            repo.getFileContent(path);
        } catch (FileNotFoundException e) {
            log.info("Image tag store {} not found. Creating a new image tag store",
                    path);
            repo.createContent().content("").message("initializing store").path(path).commit();
        } catch (IOException ex) {
            if (ex.getMessage().contains("too_large")) {
                log.info("Image tag store {} is already initialized and has size more than 1 MB",
                        path);
            } else {
                throw ex;
            }
        }
    }

    protected void updateStoreOnGithub(GHRepository repo, String path, String img, String tag) throws IOException {
        initializeTagStoreIfRequired(repo, path);

        GHCommit commit = repo.getCommit(repo.getDefaultBranch());
        GHBlob blob = commit.getTree().getEntry(path).asBlob();
        JsonElement json = null;

        String text;
        try (InputStream stream = blob.read()) {
            text = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
            json = JsonParser.parseString(text);
        } catch (JsonParseException e) {
            log.warn("Not a JSON formatted store. Clearing and rewriting as JSON...");
            json = JsonNull.INSTANCE;
        }

        String jsonOutput = getAndModifyJsonString(json, img, tag);

        String treeSha = repo
                .createTree()
                .baseTree(commit.getSHA1())
                .add(path, jsonOutput, false).create().getSha();

        String commitSha = repo.createCommit()
                .message(String.format("Updated image %s with tag %s.%n@rev none@", img, tag))
                .tree(treeSha)
                .parent(commit.getSHA1())
                .create()
                .getSHA1();
        repo.getRef("heads/" + repo.getDefaultBranch()).updateTo(commitSha);
    }

    protected String getAndModifyJsonString(JsonElement json, String img, String tag) {
        JsonElement images;
        if (json.isJsonNull()) {
            json = new JsonObject();
            images = new JsonObject();
            json.getAsJsonObject().add("images", images);
        }
        images = json.getAsJsonObject().get("images");
        if (images == null) {
            images = new JsonObject();
            json.getAsJsonObject().add("images", images);
            images = json.getAsJsonObject().get("images");
        }
        JsonElement newTag = new JsonPrimitive(tag);
        images.getAsJsonObject().add(img, newTag);

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        return gson.toJson(json);
    }

    public Set> parseStoreToImagesMap(DockerfileGitHubUtil dockerfileGitHubUtil, String storeName)
            throws IOException {
        GHMyself myself = dockerfileGitHubUtil.getMyself();
        String login = myself.getLogin();
        GHRepository store = dockerfileGitHubUtil.getRepo(Paths.get(login, storeName).toString());

        GHBlob storeContent = dockerfileGitHubUtil.tryRetrievingBlob(store,
                Constants.STORE_JSON_FILE, store.getDefaultBranch());

        if (storeContent == null) {
            return Collections.emptySet();
        }

        JsonElement json;
        try (InputStream stream = storeContent.read(); InputStreamReader streamR = new InputStreamReader(stream)) {
            try {
                json = JsonParser.parseReader(streamR);
            } catch (JsonParseException e) {
                log.warn("Not a JSON format store.");
                return Collections.emptySet();
            }
        }

        JsonElement imagesJson = json.getAsJsonObject().get("images");
        return imagesJson.getAsJsonObject().entrySet();
    }

    public List getStoreContent(DockerfileGitHubUtil dockerfileGitHubUtil, String storeName)
            throws IOException {
        Set> imageToTagStore = parseStoreToImagesMap(dockerfileGitHubUtil, storeName);
        return imageToTagStore.stream()
                .map(entry -> new ImageTagStoreContent(entry.getKey(), entry.getValue().getAsString()))
                .collect(Collectors.toList());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy