mirror of
https://github.com/redhat-actions/push-to-registry.git
synced 2025-02-22 18:21:20 +01:00
Check and enforce lowercasing of registry and image refs. (#56)
This commit is contained in:
parent
7e7aa10ef2
commit
ac5a9d0fd8
4 changed files with 96 additions and 16 deletions
65
.github/workflows/check-lowercase.yaml
vendored
Normal file
65
.github/workflows/check-lowercase.yaml
vendored
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# This workflow will perform a test whenever there
|
||||||
|
# is some change in code done to ensure that the changes
|
||||||
|
# are not buggy and we are getting the desired output.
|
||||||
|
name: Check Case Normalization
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *' # every day at midnight
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: ImageCaseTest
|
||||||
|
IMAGE_TAGS: v1 TagCaseTest ${{ github.sha }}
|
||||||
|
IMAGE_REGISTRY: Ghcr.io/${{ github.repository_owner }}
|
||||||
|
REGISTRY_USER: ${{ github.actor }}
|
||||||
|
REGISTRY_PASSWORD: ${{ github.token }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push-ghcr:
|
||||||
|
name: Build and push image
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
install_latest: [ true, false ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checkout push-to-registry action github repository
|
||||||
|
- name: Checkout Push to Registry action
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install latest podman
|
||||||
|
if: matrix.install_latest
|
||||||
|
run: |
|
||||||
|
bash .github/install_latest_podman.sh
|
||||||
|
|
||||||
|
# Build image using Buildah action
|
||||||
|
- name: Build Image
|
||||||
|
id: build_image
|
||||||
|
uses: redhat-actions/buildah-build@v2
|
||||||
|
with:
|
||||||
|
image: ${{ env.IMAGE_NAME }}
|
||||||
|
tags: ${{ env.IMAGE_TAGS }}
|
||||||
|
base-image: busybox:latest
|
||||||
|
entrypoint: |
|
||||||
|
bash
|
||||||
|
-c
|
||||||
|
echo 'hello world'
|
||||||
|
oci: true
|
||||||
|
|
||||||
|
# Push the image to GHCR (Image Registry)
|
||||||
|
- name: Push To GHCR
|
||||||
|
uses: ./
|
||||||
|
id: push
|
||||||
|
with:
|
||||||
|
image: ${{ steps.build_image.outputs.image }}
|
||||||
|
tags: ${{ steps.build_image.outputs.tags }}
|
||||||
|
registry: ${{ env.IMAGE_REGISTRY }}
|
||||||
|
username: ${{ env.REGISTRY_USER }}
|
||||||
|
password: ${{ env.REGISTRY_PASSWORD }}
|
||||||
|
extra-args: |
|
||||||
|
--disable-content-trust
|
||||||
|
|
||||||
|
- name: Echo outputs
|
||||||
|
run: |
|
||||||
|
echo "${{ toJSON(steps.push.outputs) }}"
|
2
dist/index.js
vendored
2
dist/index.js
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
43
src/index.ts
43
src/index.ts
|
@ -43,7 +43,7 @@ async function getPodmanPath(): Promise<string> {
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
const DEFAULT_TAG = "latest";
|
const DEFAULT_TAG = "latest";
|
||||||
const imageInput = core.getInput(Inputs.IMAGE);
|
const image = core.getInput(Inputs.IMAGE);
|
||||||
const tags = core.getInput(Inputs.TAGS);
|
const tags = core.getInput(Inputs.TAGS);
|
||||||
// split tags
|
// split tags
|
||||||
const tagsList = tags.trim().split(/\s+/);
|
const tagsList = tags.trim().split(/\s+/);
|
||||||
|
@ -53,6 +53,21 @@ async function run(): Promise<void> {
|
||||||
core.info(`Input "${Inputs.TAGS}" is not provided, using default tag "${DEFAULT_TAG}"`);
|
core.info(`Input "${Inputs.TAGS}" is not provided, using default tag "${DEFAULT_TAG}"`);
|
||||||
tagsList.push(DEFAULT_TAG);
|
tagsList.push(DEFAULT_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedTagsList: string[] = [];
|
||||||
|
let isNormalized = false;
|
||||||
|
for (const tag of tagsList) {
|
||||||
|
normalizedTagsList.push(tag.toLowerCase());
|
||||||
|
if (tag.toLowerCase() !== tag) {
|
||||||
|
isNormalized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const normalizedImage = image.toLowerCase();
|
||||||
|
if (isNormalized || image !== normalizedImage) {
|
||||||
|
core.warning(`Reference to image and/or tag must be lowercase.`
|
||||||
|
+ ` Reference has been converted to be compliant with standard.`);
|
||||||
|
}
|
||||||
|
|
||||||
const registry = core.getInput(Inputs.REGISTRY);
|
const registry = core.getInput(Inputs.REGISTRY);
|
||||||
const username = core.getInput(Inputs.USERNAME);
|
const username = core.getInput(Inputs.USERNAME);
|
||||||
const password = core.getInput(Inputs.PASSWORD);
|
const password = core.getInput(Inputs.PASSWORD);
|
||||||
|
@ -60,12 +75,12 @@ async function run(): Promise<void> {
|
||||||
const digestFileInput = core.getInput(Inputs.DIGESTFILE);
|
const digestFileInput = core.getInput(Inputs.DIGESTFILE);
|
||||||
|
|
||||||
// check if all tags provided are in `image:tag` format
|
// check if all tags provided are in `image:tag` format
|
||||||
const isFullImageNameTag = isFullImageName(tagsList[0]);
|
const isFullImageNameTag = isFullImageName(normalizedTagsList[0]);
|
||||||
if (tagsList.some((tag) => isFullImageName(tag) !== isFullImageNameTag)) {
|
if (normalizedTagsList.some((tag) => isFullImageName(tag) !== isFullImageNameTag)) {
|
||||||
throw new Error(`Input "${Inputs.TAGS}" cannot have a mix of full name and non full name tags`);
|
throw new Error(`Input "${Inputs.TAGS}" cannot have a mix of full name and non full name tags`);
|
||||||
}
|
}
|
||||||
if (!isFullImageNameTag) {
|
if (!isFullImageNameTag) {
|
||||||
if (!imageInput) {
|
if (!normalizedImage) {
|
||||||
throw new Error(`Input "${Inputs.IMAGE}" must be provided when using non full name tags`);
|
throw new Error(`Input "${Inputs.IMAGE}" must be provided when using non full name tags`);
|
||||||
}
|
}
|
||||||
if (!registry) {
|
if (!registry) {
|
||||||
|
@ -73,28 +88,28 @@ async function run(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const registryWithoutTrailingSlash = registry.replace(/\/$/, "");
|
const registryWithoutTrailingSlash = registry.replace(/\/$/, "");
|
||||||
const registryPath = `${registryWithoutTrailingSlash}/${imageInput}`;
|
const registryPath = `${registryWithoutTrailingSlash}/${normalizedImage}`;
|
||||||
core.info(`Combining image name "${imageInput}" and registry "${registry}" `
|
core.info(`Combining image name "${normalizedImage}" and registry "${registry}" `
|
||||||
+ `to form registry path "${registryPath}"`);
|
+ `to form registry path "${registryPath}"`);
|
||||||
if (imageInput.indexOf("/") > -1 && registry.indexOf("/") > -1) {
|
if (normalizedImage.indexOf("/") > -1 && registry.indexOf("/") > -1) {
|
||||||
core.warning(`"${registryPath}" does not seem to be a valid registry path. `
|
core.warning(`"${registryPath}" does not seem to be a valid registry path. `
|
||||||
+ `The registry path should not contain more than 2 slashes. `
|
+ `The registry path should not contain more than 2 slashes. `
|
||||||
+ `Refer to the Inputs section of the readme for naming image and registry.`);
|
+ `Refer to the Inputs section of the readme for naming image and registry.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceImages = tagsList.map((tag) => getFullImageName(imageInput, tag));
|
sourceImages = normalizedTagsList.map((tag) => getFullImageName(normalizedImage, tag));
|
||||||
destinationImages = tagsList.map((tag) => getFullImageName(registryPath, tag));
|
destinationImages = normalizedTagsList.map((tag) => getFullImageName(registryPath, tag));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (imageInput) {
|
if (normalizedImage) {
|
||||||
core.warning(`Input "${Inputs.IMAGE}" is ignored when using full name tags`);
|
core.warning(`Input "${Inputs.IMAGE}" is ignored when using full name tags`);
|
||||||
}
|
}
|
||||||
if (registry) {
|
if (registry) {
|
||||||
core.warning(`Input "${Inputs.REGISTRY}" is ignored when using full name tags`);
|
core.warning(`Input "${Inputs.REGISTRY}" is ignored when using full name tags`);
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceImages = tagsList;
|
sourceImages = normalizedTagsList;
|
||||||
destinationImages = tagsList;
|
destinationImages = normalizedTagsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputExtraArgsStr = core.getInput(Inputs.EXTRA_ARGS);
|
const inputExtraArgsStr = core.getInput(Inputs.EXTRA_ARGS);
|
||||||
|
@ -157,8 +172,8 @@ async function run(): Promise<void> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const allTagsinPodman: boolean = podmanFoundTags.length === tagsList.length;
|
const allTagsinPodman: boolean = podmanFoundTags.length === normalizedTagsList.length;
|
||||||
const allTagsinDocker: boolean = dockerFoundTags.length === tagsList.length;
|
const allTagsinDocker: boolean = dockerFoundTags.length === normalizedTagsList.length;
|
||||||
|
|
||||||
if (allTagsinPodman && allTagsinDocker) {
|
if (allTagsinPodman && allTagsinDocker) {
|
||||||
const isPodmanImageLatest = await isPodmanLocalImageLatest();
|
const isPodmanImageLatest = await isPodmanLocalImageLatest();
|
||||||
|
|
Loading…
Add table
Reference in a new issue