diff --git a/.github/workflows/include-kcl-checksums.yml b/.github/workflows/include-kcl-checksums.yml new file mode 100644 index 00000000..8a1fce9f --- /dev/null +++ b/.github/workflows/include-kcl-checksums.yml @@ -0,0 +1,31 @@ +name: Include KCL Modules Checksum + +on: + push: + +jobs: + include_modules_checksum: + runs-on: ubuntu-latest + + steps: + - name: Install kcl + run: wget -q https://kcl-lang.io/script/install-cli.sh -O - | /bin/bash + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Login to GHCR + run: kcl registry login -u ${{ secrets.DEPLOY_ACCESS_NAME }} -p ${{ secrets.DEPLOY_ACCESS_TOKEN }} ghcr.io + + - name: Get dependencies + run: go get -v ./... + + - name: Run include checksum tool + run: go run ./Integrate-Checksum/main.go diff --git a/Integrate-Checksum/main.go b/Integrate-Checksum/main.go index 764d3999..afbd2a4e 100644 --- a/Integrate-Checksum/main.go +++ b/Integrate-Checksum/main.go @@ -215,4 +215,6 @@ func main() { fmt.Printf("Error processing package at '%s': %v\n", packageDir, err) } } + + fmt.Println("Checksum successfully included in all KCL packages") } diff --git a/Integrate-Checksum/main_test.go b/Integrate-Checksum/main_test.go new file mode 100644 index 00000000..589322fd --- /dev/null +++ b/Integrate-Checksum/main_test.go @@ -0,0 +1,100 @@ +package main + +import ( + "encoding/json" + "os" + "runtime" + "testing" + + "artifacthub/mock" + + "gotest.tools/assert" + "kcl-lang.io/kpm/pkg/client" + "kcl-lang.io/kpm/pkg/constants" +) + +// TestMainFunc tests the main functionality of the integrate checksum tool +func TestMainFunc(t *testing.T) { + // Skip the test on Windows due to platform-specific issues. + if runtime.GOOS == "windows" { + t.Skip("Skipping TestMainFunc on Windows due to platform-specific issues") + } + + // Start the local Docker registry required for testing + err := mock.StartDockerRegistry() + assert.NilError(t, err) + + // Push the test package to the local OCI registry + err = mock.PushTestPkgToRegistry() + assert.NilError(t, err) + + // Initialize the KPM client. + kpmClient, err := client.NewKpmClient() + assert.NilError(t, err, "Failed to initialize KPM client") + + // Get the current working directory. + currentDir, err := os.Getwd() + assert.NilError(t, err, "Failed to get current working directory") + + // Locate KCL module files in the current directory. + packageDirs, err := findKCLModFiles(currentDir) + assert.NilError(t, err, "Failed to locate KCL module files") + assert.Assert(t, len(packageDirs) > 0, "No KCL module files found") + + // Resolve the dependency for the first module found. + dependency, err := resolveDependency(kpmClient, packageDirs[0]) + assert.NilError(t, err, "Failed to resolve dependency") + + // Set custom OCI registry and repository for testing. + dependency.Source.Oci.Reg = "localhost:5001" + dependency.Source.Oci.Repo = "test" + + // Fetch the original manifest. + originalManifest, err := fetchManifest(kpmClient, dependency) + assert.NilError(t, err, "Failed to fetch original manifest") + + // Marshal the original manifest into JSON format. + originalManifestJSON, err := json.Marshal(originalManifest) + assert.NilError(t, err, "Failed to marshal original manifest to JSON") + + // Configure the repository for testing purposes. + repository, err := configureRepository(dependency, kpmClient) + assert.NilError(t, err, "Failed to configure repository") + repository.PlainHTTP = true // Enable plain HTTP for local testing. + + // Modify the manifest annotations for testing. + originalManifest.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM] = "changes-for-testing-purpose" + + // Marshal the updated manifest into JSON format. + updatedManifestJSON, err := json.Marshal(originalManifest) + assert.NilError(t, err, "Failed to marshal updated manifest to JSON") + + // Tag the updated manifest in the repository. + err = tagManifest(repository, updatedManifestJSON, dependency) + assert.NilError(t, err, "Failed to tag updated manifest in repository") + + // Fetch the new manifest after tagging. + newManifest, err := fetchManifest(kpmClient, dependency) + assert.NilError(t, err, "Failed to fetch new manifest") + + // Marshal the new manifest into JSON format for comparison. + newManifestJSON, err := json.Marshal(newManifest) + assert.NilError(t, err, "Failed to marshal new manifest to JSON") + + // Check if the manifest was updated correctly. + if string(newManifestJSON) == string(originalManifestJSON) { + t.Errorf("Failed to update the manifest; got %v", string(originalManifestJSON)) + } + + // Revert the `Sum` field to its original value to ensure only that was changed. + newManifest.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM] = dependency.Sum + newManifestJSON, err = json.Marshal(newManifest) + assert.NilError(t, err, "Failed to marshal reverted manifest to JSON") + + // Compare the new manifest data with the expected manifest data. + assert.Equal(t, string(newManifestJSON), string(originalManifestJSON), "New manifest data mismatch") + + // Clean the environment after all tests have been run + err = mock.CleanTestEnv() + assert.NilError(t, err) +} diff --git a/Integrate-Checksum/test_data/kcl.mod b/Integrate-Checksum/test_data/kcl.mod new file mode 100644 index 00000000..6c01364d --- /dev/null +++ b/Integrate-Checksum/test_data/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "test_data" +edition = "v0.9.0" +version = "0.0.1" + +[dependencies] +k8s = "1.31" + diff --git a/Integrate-Checksum/test_data/kcl.mod.lock b/Integrate-Checksum/test_data/kcl.mod.lock new file mode 100644 index 00000000..41b4867f --- /dev/null +++ b/Integrate-Checksum/test_data/kcl.mod.lock @@ -0,0 +1,5 @@ +[dependencies] + [dependencies.k8s] + name = "k8s" + full_name = "k8s_1.31" + version = "1.31" diff --git a/Integrate-Checksum/test_data/main.k b/Integrate-Checksum/test_data/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/Integrate-Checksum/test_data/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/mock/oci_env_mock.go b/mock/oci_env_mock.go new file mode 100644 index 00000000..4ebd5819 --- /dev/null +++ b/mock/oci_env_mock.go @@ -0,0 +1,23 @@ +package mock + +import ( + "os/exec" +) + +// StartDockerRegistry starts a local Docker registry by executing a shell script. +func StartDockerRegistry() error { + cmd := exec.Command("../scripts/reg.sh") + return cmd.Run() +} + +// PushTestPkgToRegistry pushes the test package to the local Docker registry. +func PushTestPkgToRegistry() error { + cmd := exec.Command("../mock/test_script/push_pkg.sh") + return cmd.Run() +} + +// CleanTestEnv cleans up the test environment by executing a cleanup script. +func CleanTestEnv() error { + cmd := exec.Command("../mock/test_script/cleanup_test_environment.sh") + return cmd.Run() +} diff --git a/mock/test_data/kcl.mod b/mock/test_data/kcl.mod new file mode 100644 index 00000000..6c01364d --- /dev/null +++ b/mock/test_data/kcl.mod @@ -0,0 +1,8 @@ +[package] +name = "test_data" +edition = "v0.9.0" +version = "0.0.1" + +[dependencies] +k8s = "1.31" + diff --git a/mock/test_data/kcl.mod.lock b/mock/test_data/kcl.mod.lock new file mode 100644 index 00000000..41b4867f --- /dev/null +++ b/mock/test_data/kcl.mod.lock @@ -0,0 +1,5 @@ +[dependencies] + [dependencies.k8s] + name = "k8s" + full_name = "k8s_1.31" + version = "1.31" diff --git a/mock/test_data/main.k b/mock/test_data/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/mock/test_data/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/mock/test_script/cleanup_test_environment.sh b/mock/test_script/cleanup_test_environment.sh new file mode 100755 index 00000000..4a244a01 --- /dev/null +++ b/mock/test_script/cleanup_test_environment.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Determine the directory where this script is located +SCRIPT_DIR="$(dirname "$(realpath "$0")")" + +# Stop and remove the Docker container then remove the Docker image +docker stop kcl-registry +docker rm kcl-registry +docker rmi registry + +# Delete all data stored in the Docker registry volume +rm -rf /var/lib/registry/* + +# Remove the directory that contains Docker authentication and related scripts +current_dir=$(pwd) +rm -rf "$current_dir/scripts/" + +# Delete the 'kcl' binary +cd "$SCRIPT_DIR/../../" +rm -rf ./bin/ diff --git a/mock/test_script/push_pkg.sh b/mock/test_script/push_pkg.sh new file mode 100755 index 00000000..999065aa --- /dev/null +++ b/mock/test_script/push_pkg.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Get the directory of the script +SCRIPT_DIR="$(dirname "$(realpath "$0")")" + +# Move to the root directory +cd "$SCRIPT_DIR/../../" + +# Install kcl binary +GOBIN=$(pwd)/bin go install kcl-lang.io/cli/cmd/kcl@latest + +# Check kpm version +version=$(./bin/kcl --version) +if ! echo "$version" ; then + echo "Incorrect version: '$version'." + exit 1 +fi + +export KPM_REG="localhost:5001" +export KPM_REPO="test" + +# Prepare the package on the registry +current_dir=$(pwd) +echo $current_dir + +# Log in to the local registry +"$current_dir/bin/kcl" registry login -u test -p 1234 localhost:5001 + +# Push the test_data package to the registry +cd "$SCRIPT_DIR/../test_data" +"$current_dir/bin/kcl" mod push oci://$KPM_REG/$KPM_REPO