diff --git a/.circleci/config.yml b/.circleci/config.yml index edb870e9a..4da7021ac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,7 +105,55 @@ jobs: name: install dependencies command: | go mod vendor - - run: sudo chown circleci:circleci $GOPATH/bin + - run: + name: install node16 npm and npx + command: | + sudo apt-get update + curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - + sudo apt-get install -y nodejs + echo "node version:" + node --version + echo "npm version:" + npm --version + echo "npx version:" + npx --version + - run: + name: install cyclonedx-cli + command: | + CYCLONEDX_CLI_VERSION=0.24.2 + CYCLONEDX_BINARY_NAME=cyclonedx + CYCLONEDX_ARCH=x64 + CYCLONEDX_OS=linux + curl -fsSLO --compressed "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v${CYCLONEDX_CLI_VERSION}/${CYCLONEDX_BINARY_NAME}-${CYCLONEDX_OS}-${CYCLONEDX_ARCH}" + chmod ug+rwx ${CYCLONEDX_BINARY_NAME}-${CYCLONEDX_OS}-${CYCLONEDX_ARCH} + cp ${CYCLONEDX_BINARY_NAME}-${CYCLONEDX_OS}-${CYCLONEDX_ARCH} ${GOPATH}/bin/${CYCLONEDX_BINARY_NAME} + echo "cyclonedx-cli --version:" + ${CYCLONEDX_BINARY_NAME} --version + - run: + name: install cyclonedx-gomod + command: | + echo "cyclonedx-gomod version" + go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest + cyclonedx-gomod version + - run: + name: install cyclonedx-bom + command: | + CYCLONEDX_BOM_PACKAGE=cyclonedx-bom + CYCLONEDX_BOM_VERSION=0.0.9 + CYCLONEDX_BOM_BINARY=cyclonedx-bom + npm install ${CYCLONEDX_BOM_PACKAGE}@${CYCLONEDX_BOM_VERSION} --no-save + echo "${CYCLONEDX_BOM_BINARY} -h" + npx ${CYCLONEDX_BOM_BINARY} -h + - run: + name: build mbt binary + command: | + BINARY_NAME=mbt + BUILD_DIR=release + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BUILD_DIR}/${BINARY_NAME} -v + chmod ug+rwx ${BUILD_DIR}/${BINARY_NAME} + cp ${BUILD_DIR}/${BINARY_NAME} ${GOPATH}/bin/${BINARY_NAME} + ${BINARY_NAME} --version + - run: sudo chown circleci:circleci ${GOPATH}/bin - run: make tools - run: make lint - run: @@ -793,15 +841,7 @@ workflows: only: /release/ branches: ignore: /.*/ - # - release-to-github: - # requires: - # - test - # filters: - # tags: - # only: /release/ - # branches: - # ignore: /.*/ - - publish-to-npm: + - release-to-github: requires: - test filters: @@ -809,6 +849,14 @@ workflows: only: /release/ branches: ignore: /.*/ + - publish-to-npm: + requires: + - release-to-github + filters: + tags: + only: /release/ + branches: + ignore: /.*/ - publish-to-dockerhub-java8-node14: requires: - publish-to-npm diff --git a/Dockerfile_mbtci_template b/Dockerfile_mbtci_template index cbb889e5c..3559aa349 100644 --- a/Dockerfile_mbtci_template +++ b/Dockerfile_mbtci_template @@ -10,6 +10,13 @@ ARG MAVEN_VERSION=3.9.4 ARG UI5_VERSION=2.14.19 ARG MAVEN_BASE_URL=https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries ARG SAPMACHINE_VERSION=JAVA_VERSION_TEMPLATE +ARG CYCLONEDX_CLI_VERSION=0.24.2 +ARG CYCLONEDX_CLI_BINARY=cyclonedx +ARG CYCLONEDX_GOMOD_VERSION=1.4.0 +ARG CYCLONEDX_GOMOD_BINARY=cyclonedx-gomod +ARG CYCLONEDX_BOM_PACKAGE=cyclonedx-bom +ARG CYCLONEDX_BOM_VERSION=0.0.9 +ARG CYCLONEDX_BOM_BINARY=cyclonedx-bom # Environment variables ENV PYTHON /usr/bin/python3 @@ -29,172 +36,172 @@ RUN set -ex \ # smoke test && openssl version \ && useradd --home-dir ${MTA_USER_HOME} \ - --create-home \ - --shell /bin/bash \ - --user-group \ - --uid 1000 \ - --comment 'Cloud MTA Build Tool' \ - --password "$(echo weUseMta | openssl passwd -1 -stdin)" ${MTA_USER} \ + --create-home \ + --shell /bin/bash \ + --user-group \ + --uid 1000 \ + --comment 'Cloud MTA Build Tool' \ + --password "$(echo weUseMta | openssl passwd -1 -stdin)" ${MTA_USER} \ # allow anybody to write into the image user home directory && chmod a+w ${MTA_USER_HOME} \ && apt-get remove --purge --autoremove -y openssl # Download SAP_Global_Root_CA.crt to target ADD http://aia.pki.co.sap.com/aia/SAP%20Global%20Root%20CA.crt \ - /etc/ssl/certs/SAP_Global_Root_CA.crt + /etc/ssl/certs/SAP_Global_Root_CA.crt # Install Node.js RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ - && case "${dpkgArch##*-}" in \ - amd64) ARCH='x64';; \ - ppc64el) ARCH='ppc64le';; \ - s390x) ARCH='s390x';; \ - arm64) ARCH='arm64';; \ - armhf) ARCH='armv7l';; \ - i386) ARCH='x86';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac \ - && set -ex \ - && apt-get update \ - # libatomic1 for arm - && apt-get install -y ca-certificates curl gnupg dirmngr xz-utils libatomic1 --no-install-recommends \ - && rm -rf /var/lib/apt/lists/* \ - && export GNUPGHOME="$(mktemp -d)" \ - && for key in \ - 4ED778F539E3634C779C87C6D7062848A1AB005C \ - 141F07595B7B3FFE74309A937405533BE57C7D57 \ - 74F12602B6F1C4E913FAA37AD3A89613643B6201 \ - DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ - 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ - C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ - 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ - C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ - 108F52B48DB57BB0CC439B2997B01419BD92F80A \ - ; do \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ - gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ - done \ - && curl -fsSLO --compressed "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" \ - && curl -fsSLO --compressed "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt.asc" \ - && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ - && grep " node-v${NODE_VERSION}-linux-${ARCH}.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ - && tar -xJf "node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ - && rm -rf "$GNUPGHOME" "node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ - && apt-mark auto '.*' > /dev/null \ - && find /usr/local -type f -executable -exec ldd '{}' ';' \ - | awk '/=>/ { print $(NF-1) }' \ - | sort -u \ - | xargs -r dpkg-query --search \ - | cut -d: -f1 \ - | sort -u \ - | xargs -r apt-mark manual \ - && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ - && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ - # smoke tests - && echo "node ${NODE_VERSION} install smoke tests!" \ - && node --version \ - && npm --version + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + ppc64el) ARCH='ppc64le';; \ + s390x) ARCH='s390x';; \ + arm64) ARCH='arm64';; \ + armhf) ARCH='armv7l';; \ + i386) ARCH='x86';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update \ + # libatomic1 for arm + && apt-get install -y ca-certificates curl gnupg dirmngr xz-utils libatomic1 --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + && export GNUPGHOME="$(mktemp -d)" \ + && for key in \ + 4ED778F539E3634C779C87C6D7062848A1AB005C \ + 141F07595B7B3FFE74309A937405533BE57C7D57 \ + 74F12602B6F1C4E913FAA37AD3A89613643B6201 \ + DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 \ + 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ + C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ + 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 \ + C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ + 108F52B48DB57BB0CC439B2997B01419BD92F80A \ + ; do \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ + gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ + done \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" \ + && curl -fsSLO --compressed "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt.asc" \ + && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ + && grep " node-v${NODE_VERSION}-linux-${ARCH}.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ + && tar -xJf "node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm -rf "$GNUPGHOME" "node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ + && apt-mark auto '.*' > /dev/null \ + && find /usr/local -type f -executable -exec ldd '{}' ';' \ + | awk '/=>/ { print $(NF-1) }' \ + | sort -u \ + | xargs -r dpkg-query --search \ + | cut -d: -f1 \ + | sort -u \ + | xargs -r apt-mark manual \ + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ + # smoke tests + && echo "node ${NODE_VERSION} install smoke tests!" \ + && node --version \ + && npm --version # Install Grunt CLI RUN set -ex \ - && npm install --prefix /usr/local/ -g grunt-cli \ - && npm cache clean -g --force \ - # smoke test - && echo "grunt-cli install smoke test!" \ - && grunt --version + && npm install --prefix /usr/local/ -g grunt-cli \ + && npm cache clean -g --force \ + # smoke test + && echo "grunt-cli install smoke test!" \ + && grunt --version # Install UI5 CLI RUN set -ex \ - && npm install --prefix /usr/local/ -g @ui5/cli@${UI5_VERSION} \ - && npm cache clean -g --force \ - # smoke test - && echo "ui5 install smoke test!" \ - && ui5 --version + && npm install --prefix /usr/local/ -g @ui5/cli@${UI5_VERSION} \ + && npm cache clean -g --force \ + # smoke test + && echo "ui5 install smoke test!" \ + && ui5 --version # Install Golang RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ - && case "${dpkgArch##*-}" in \ - i386) ARCH='386';; \ - amd64) ARCH='amd64';; \ - ppc64el) ARCH='ppc64le';; \ - s390x) ARCH='s390x';; \ - arm64) ARCH='arm64';; \ - armhf) ARCH='armv6l';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac \ - && set -ex \ - && apt-get update \ - && apt-get install -y ca-certificates curl gnupg dirmngr --no-install-recommends \ - && rm -rf /var/lib/apt/lists/* \ - && export GNUPGHOME="$(mktemp -d)" \ - && for key in \ - EB4C1BFD4F042F6DDDCCEC917721F63BD38B4796 \ - 2F528D36D67B69EDF998D85778BD65473CB3BD13 \ - ; do \ - gpg --batch --keyserver hkps://pgp.surf.nl --recv-keys "$key" || \ - gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ - done \ - && curl -fsSLO --compressed https://storage.googleapis.com/golang/go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz \ - && curl -fsSLO --compressed https://storage.googleapis.com/golang/go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc \ - && gpg --batch --verify go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz \ - && tar -xvf go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz -C /usr/local \ - && rm -rf "$GNUPGHOME" go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc \ - && apt-get remove --purge --autoremove -y ca-certificates curl gnupg dirmngr \ - # smoke test - && echo "go ${GO_VERSION} install smoke test!" \ - && go version + && case "${dpkgArch##*-}" in \ + i386) ARCH='386';; \ + amd64) ARCH='amd64';; \ + ppc64el) ARCH='ppc64le';; \ + s390x) ARCH='s390x';; \ + arm64) ARCH='arm64';; \ + armhf) ARCH='armv6l';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update \ + && apt-get install -y ca-certificates curl gnupg dirmngr --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + && export GNUPGHOME="$(mktemp -d)" \ + && for key in \ + EB4C1BFD4F042F6DDDCCEC917721F63BD38B4796 \ + 2F528D36D67B69EDF998D85778BD65473CB3BD13 \ + ; do \ + gpg --batch --keyserver hkps://pgp.surf.nl --recv-keys "$key" || \ + gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ + done \ + && curl -fsSLO --compressed https://storage.googleapis.com/golang/go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz \ + && curl -fsSLO --compressed https://storage.googleapis.com/golang/go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc \ + && gpg --batch --verify go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz \ + && tar -xvf go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz -C /usr/local \ + && rm -rf "$GNUPGHOME" go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz go${GO_VERSION}.${GOOS}-${ARCH}.tar.gz.asc \ + && apt-get remove --purge --autoremove -y ca-certificates curl gnupg dirmngr \ + # smoke test + && echo "go ${GO_VERSION} install smoke test!" \ + && go version # Install SAPMachine RUN sapmachine_install() { \ - SAPMACHINE_MAJOR_VERSION=$(echo ${SAPMACHINE_VERSION} | cut -d. -f1); \ - ARCH=; \ - dpkgArch="$(dpkg --print-architecture)"; \ - case "${dpkgArch##*-}" in \ - amd64) ARCH='amd64';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac; \ - apt-get update; \ - apt-get install -y ca-certificates gnupg dirmngr --no-install-recommends; \ - rm -rf /var/lib/apt/lists/*; \ - export GNUPGHOME="$(mktemp -d)"; \ - for key in \ - CACB9FE09150307D1D22D82962754C3B3ABCFE23 \ - ; do \ - gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/sapmachine.gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ - gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/sapmachine.gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ - done; \ - chmod 644 /etc/apt/trusted.gpg.d/sapmachine.gpg; \ - echo "deb http://dist.sapmachine.io/debian/${ARCH}/ ./" | tee /etc/apt/sources.list.d/sapmachine.list; \ - apt-get update; \ - apt-get install -y sapmachine-${SAPMACHINE_MAJOR_VERSION}-jdk=${SAPMACHINE_VERSION} --no-install-recommends; \ - rm -rf "$GNUPGHOME" /var/lib/apt/lists/*; \ - apt-get remove --purge --autoremove -y ca-certificates gnupg dirmngr; \ - ln -s /usr/lib/jvm/sapmachine-${SAPMACHINE_MAJOR_VERSION} ${JAVA_HOME}; \ + SAPMACHINE_MAJOR_VERSION=$(echo ${SAPMACHINE_VERSION} | cut -d. -f1); \ + ARCH=; \ + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + amd64) ARCH='amd64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac; \ + apt-get update; \ + apt-get install -y ca-certificates gnupg dirmngr --no-install-recommends; \ + rm -rf /var/lib/apt/lists/*; \ + export GNUPGHOME="$(mktemp -d)"; \ + for key in \ + CACB9FE09150307D1D22D82962754C3B3ABCFE23 \ + ; do \ + gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/sapmachine.gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ + gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/sapmachine.gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ + done; \ + chmod 644 /etc/apt/trusted.gpg.d/sapmachine.gpg; \ + echo "deb http://dist.sapmachine.io/debian/${ARCH}/ ./" | tee /etc/apt/sources.list.d/sapmachine.list; \ + apt-get update; \ + apt-get install -y sapmachine-${SAPMACHINE_MAJOR_VERSION}-jdk=${SAPMACHINE_VERSION} --no-install-recommends; \ + rm -rf "$GNUPGHOME" /var/lib/apt/lists/*; \ + apt-get remove --purge --autoremove -y ca-certificates gnupg dirmngr; \ + ln -s /usr/lib/jvm/sapmachine-${SAPMACHINE_MAJOR_VERSION} ${JAVA_HOME}; \ }; \ sapjvm_install() { \ - ARCH=; \ - dpkgArch="$(dpkg --print-architecture)"; \ - case "${dpkgArch##*-}" in \ - amd64) ARCH='x64';; \ - ppc64el) ARCH='ppc64le';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac; \ - apt-get update; \ - apt-get install -y ca-certificates curl libarchive-tools --no-install-recommends; \ - rm -rf /var/lib/apt/lists/*; \ - curl -fsSLO --compressed -b 'eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt' https://tools.hana.ondemand.com/additional/sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip; \ - echo "7d63f20b17becb5f658d413c113ea9efdfbba6a0 sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip" | sha1sum -c -; \ - bsdtar -xvf sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip -C /usr/local --strip-components=1 --no-same-owner; \ - rm -f sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip; \ - apt-get remove --purge --auto-remove -y ca-certificates curl libarchive-tools; \ - ln -s /usr/local ${JAVA_HOME}; \ + ARCH=; \ + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + ppc64el) ARCH='ppc64le';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac; \ + apt-get update; \ + apt-get install -y ca-certificates curl libarchive-tools --no-install-recommends; \ + rm -rf /var/lib/apt/lists/*; \ + curl -fsSLO --compressed -b 'eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt' https://tools.hana.ondemand.com/additional/sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip; \ + echo "7d63f20b17becb5f658d413c113ea9efdfbba6a0 sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip" | sha1sum -c -; \ + bsdtar -xvf sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip -C /usr/local --strip-components=1 --no-same-owner; \ + rm -f sapjvm-${SAPMACHINE_VERSION}-linux-${ARCH}.zip; \ + apt-get remove --purge --auto-remove -y ca-certificates curl libarchive-tools; \ + ln -s /usr/local ${JAVA_HOME}; \ } \ && set -ex \ && if [ $(echo ${SAPMACHINE_VERSION} | cut -d. -f1) -le 8 ]; then \ - sapjvm_install; \ - else \ - sapmachine_install; \ - fi \ + sapjvm_install; \ + else \ + sapmachine_install; \ + fi \ # smoke test && echo "SAPMachine ${SAPMACHINE_VERSION} install smoke test!" \ && java -version @@ -208,10 +215,10 @@ RUN set -ex \ && curl -fsSLO --compressed ${MAVEN_BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz.asc \ && export GNUPGHOME="$(mktemp -d)" \ && for key in \ - 29BEA2A645F2D6CED7FB12E02B172E3E156466E8 \ + 29BEA2A645F2D6CED7FB12E02B172E3E156466E8 \ ; do \ - gpg --batch --keyserver hkps://pgp.surf.nl --recv-keys "$key" || \ - gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ + gpg --batch --keyserver hkps://pgp.surf.nl --recv-keys "$key" || \ + gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "$key" ; \ done \ && gpg --batch --verify apache-maven-${MAVEN_VERSION}-bin.tar.gz.asc apache-maven-${MAVEN_VERSION}-bin.tar.gz \ && mkdir -p ${MAVEN_HOME} ${MAVEN_HOME}/ref \ @@ -249,7 +256,50 @@ RUN set -ex \ && chown -R ${MTA_USER}:${MTA_USER} ${MTA_USER_HOME} ENV NPM_CONFIG_PREFIX ${MTA_USER_HOME}/.npm-global -# Instll curl and ca-certificates +# Install cyclone-cli +RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + arm64) ARCH='arm64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update \ + && apt-get install -y ca-certificates curl gnupg dirmngr libicu-dev --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + && curl -fsSLO --compressed "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v${CYCLONEDX_CLI_VERSION}/${CYCLONEDX_CLI_BINARY}-linux-${ARCH}" \ + && chmod a+rx ${CYCLONEDX_CLI_BINARY}-linux-${ARCH} \ + && mv ${CYCLONEDX_CLI_BINARY}-linux-${ARCH} /usr/local/bin/${CYCLONEDX_CLI_BINARY} \ + && apt-get remove --purge --autoremove -y ca-certificates curl gnupg dirmngr \ + && echo "cyclonedx-cli smoke tests!" \ + && ${CYCLONEDX_CLI_BINARY} --version + +# Install cyclone-gomod +RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ + && case "${dpkgArch##*-}" in \ + amd64) ARCH='amd64';; \ + arm64) ARCH='arm64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac \ + && set -ex \ + && apt-get update \ + && apt-get install -y ca-certificates curl gnupg dirmngr libicu-dev --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + && curl -fsSLO --compressed "https://github.com/CycloneDX/cyclonedx-gomod/releases/download/v${CYCLONEDX_GOMOD_VERSION}/${CYCLONEDX_GOMOD_BINARY}_${CYCLONEDX_GOMOD_VERSION}_linux_${ARCH}.tar.gz" \ + && tar -xzf ${CYCLONEDX_GOMOD_BINARY}_${CYCLONEDX_GOMOD_VERSION}_linux_${ARCH}.tar.gz \ + && chmod a+rx ${CYCLONEDX_GOMOD_BINARY} \ + && mv ${CYCLONEDX_GOMOD_BINARY} /usr/local/bin/${CYCLONEDX_GOMOD_BINARY} \ + && apt-get remove --purge --autoremove -y ca-certificates curl gnupg dirmngr \ + && echo "cyclonedx-gomod smoke tests!" \ + && cyclonedx-gomod version + +# Install cyclone-bom +RUN set -ex \ + && npm install --prefix /usr/local/ -g ${CYCLONEDX_BOM_PACKAGE}@${CYCLONEDX_BOM_VERSION} \ + && echo "cyclonedx-bom smoke tests!" \ + && npx ${CYCLONEDX_BOM_BINARY} -h + +# Install curl and ca-certificates RUN set -ex \ && apt-get update \ && apt-get install -y curl ca-certificates --no-install-recommends diff --git a/Makefile b/Makefile index 16d68c5f6..874a8a9c6 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,9 @@ # Execute go build # Copy files to machine go/bin folder (temp target to avoid manual steps when developing locally) -all:format clean dir gen build-linux build-linux-arm build-darwin build-darwin-arm build-windows copy tests +all:format clean dir gen build-linux build-linux-arm build-darwin build-darwin-arm build-windows copy install-cyclonedx tests .PHONY: build-darwin-arm build-darwin build-linux build-linux-arm build-windows tests - GOCMD=go GOBUILD=$(GOCMD) build GOLANGCI_VERSION = 1.21.0 @@ -16,6 +15,44 @@ GOLANGCI_VERSION = 1.21.0 BINARY_NAME=mbt BUILD = $(CURDIR)/release +# cyclonedx-cli +CYCLONEDX_CLI_BINARY = cyclonedx +CYCLONEDX_CLI_VERSION = 0.24.2 + +# cyclonedx-gomod +CYCLONEDX_GOMOD_BINARY = cyclonedx-gomod +CYCLONEDX_GOMOD_VERSION = latest + +# cyclonedx-bom +CYCLONEDX_BOM_PACKAGE = cyclonedx-bom +CYCLONEDX_BOM_VERSION = 0.0.9 +CYCLONEDX_BOM_BINARY = cyclonedx-bom + + +ifeq ($(OS),Windows_NT) +CYCLONEDX_OS=win +else ifeq ($(shell uname -s), Linux) +CYCLONEDX_OS=linux +else ifeq ($(shell uname -s), Darwin) +CYCLONEDX_OS=osx +endif + +ifeq ($(shell uname -m),x86_64) + CYCLONEDX_ARCH=x64 +else ifeq ($(shell uname -m),arm64) + CYCLONEDX_ARCH=arm64 +else ifeq ($(shell uname -m),i386) + CYCLONEDX_ARCH=x86 +else + CYCLONEDX_ARCH=x64 +endif + +ifeq ($(OS),Windows_NT) + CYCLONEDX_BINARY_SUFFIX = .exe +else + CYCLONEDX_BINARY_SUFFIX = +endif + format : go fmt ./... @@ -72,4 +109,20 @@ ifeq ($(OS),Windows_NT) else cp $(CURDIR)/release/$(BINARY_NAME) $(GOPATH)/bin/ cp $(CURDIR)/release/$(BINARY_NAME) $~/usr/local/bin/ -endif \ No newline at end of file +endif + +# use for local development - > install cyclonedx-gomod, cyclonedx-cli and cyclonedx-bom +install-cyclonedx: +# install cyclonedx-gomod + go install github.com/CycloneDX/cyclonedx-gomod/cmd/${CYCLONEDX_GOMOD_BINARY}@${CYCLONEDX_GOMOD_VERSION} + echo "${CYCLONEDX_GOMOD_BINARY} version" + ${CYCLONEDX_GOMOD_BINARY} version +# install cyclonedx-cli + curl -fsSLO --compressed "https://github.com/CycloneDX/cyclonedx-cli/releases/download/v${CYCLONEDX_CLI_VERSION}/${CYCLONEDX_CLI_BINARY}-${CYCLONEDX_OS}-${CYCLONEDX_ARCH}${CYCLONEDX_BINARY_SUFFIX}" + mv ${CYCLONEDX_CLI_BINARY}-${CYCLONEDX_OS}-${CYCLONEDX_ARCH}${CYCLONEDX_BINARY_SUFFIX} $(GOPATH)/bin/${CYCLONEDX_CLI_BINARY}${CYCLONEDX_BINARY_SUFFIX} + echo "${CYCLONEDX_CLI_BINARY} version:" + ${CYCLONEDX_CLI_BINARY} --version +# install cyclonedx-bom + npm install -g ${CYCLONEDX_BOM_PACKAGE}@${CYCLONEDX_BOM_VERSION} + echo "${CYCLONEDX_BOM_BINARY} -h" + npx ${CYCLONEDX_BOM_BINARY} -h \ No newline at end of file diff --git a/cmd/cmd.go b/cmd/cmd.go index 2e2c50121..6ff921d8d 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -27,7 +27,7 @@ func init() { // Add command to the root rootCmd.AddCommand(initCmd, buildCmd, validateCmd, cleanupCmd, provideCmd, generateCmd, moduleCmd, assembleCommand, - projectCmd, mergeCmd, executeCommand, copyCmd, mtadGenCmd, soloBuildModuleCmd) + projectCmd, mergeCmd, executeCommand, copyCmd, mtadGenCmd, soloBuildModuleCmd, projectSBomGenCommand) // Build module provideCmd.AddCommand(provideModuleCmd) // generate immutable commands diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go index 669539732..7dec31e94 100644 --- a/cmd/cmd_test.go +++ b/cmd/cmd_test.go @@ -47,6 +47,11 @@ var _ = Describe("Commands", func() { }) }) +func getBuildCmdCli() string { + cli := "mbt" + return cli +} + func getTestPath(relPath ...string) string { wd, _ := os.Getwd() return filepath.Join(wd, "testdata", filepath.Join(relPath...)) diff --git a/cmd/init.go b/cmd/init.go index 0671a6935..c39ff25d8 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -23,6 +23,7 @@ var initCmdExtensions []string var initCmdMode string // flags of build command +var mbtCmdCLI string var buildCmdSrc string var buildCmdTrg string var buildCmdExtensions []string @@ -33,6 +34,7 @@ var buildCmdMode string var buildCmdJobs int var buildCmdOutputSync bool var buildCmdKeepMakefile bool +var buildCmdSBomFilePath string func init() { // set flags for init command @@ -54,7 +56,9 @@ func init() { buildCmd.Flags().IntVarP(&buildCmdJobs, "jobs", "j", 0, fmt.Sprintf(`(beta) The number of Make jobs to be executed simultaneously. The default value is the number of available CPUs (maximum %d). Used only in "verbose" mode.`, artifacts.MaxMakeParallel)) buildCmd.Flags().BoolVarP(&buildCmdOutputSync, "output-sync", "o", false, `(beta) Groups the output of each Make job and prints it when the job is complete. Used only in "verbose" mode.`) buildCmd.Flags().BoolVarP(&buildCmdKeepMakefile, "keep-makefile", "k", false, `Don't remove the generated Makefile after the build ends.`) + buildCmd.Flags().StringVarP(&buildCmdSBomFilePath, "sbom-file-path", "b", "", `(beta) The path of SBOM file, relative or absoluted; if relative path, it is relative to MTA project root; if value is empty, SBOM file will not be generated.`) _ = buildCmd.Flags().MarkHidden("keep-makefile") + // _ = buildCmd.Flags().MarkHidden("sbom-file-path") buildCmd.Flags().BoolP("help", "h", false, `Displays detailed information about the "build" command`) } @@ -85,7 +89,9 @@ var buildCmd = &cobra.Command{ // However, in some environments we might want to always use the default mbt from the path. This can be set by using environment variable MBT_USE_DEFAULT. useDefaultMbt := os.Getenv("MBT_USE_DEFAULT") == "true" // Note: we can only use the non-default mbt (i.e. the current executable name) from inside the command itself because if this function runs from other places like tests it won't point to the MBT - err := artifacts.ExecBuild(makefileTmp, buildCmdSrc, buildCmdTrg, buildCmdExtensions, buildCmdMode, buildCmdMtar, buildCmdPlatform, buildCmdStrict, buildCmdJobs, buildCmdOutputSync, os.Getwd, exec.Execute, useDefaultMbt, buildCmdKeepMakefile) + err := artifacts.ExecBuild(makefileTmp, buildCmdSrc, buildCmdTrg, buildCmdExtensions, buildCmdMode, buildCmdMtar, buildCmdPlatform, buildCmdStrict, buildCmdJobs, buildCmdOutputSync, os.Getwd, exec.Execute, useDefaultMbt, buildCmdKeepMakefile, buildCmdSBomFilePath) + // output err info to stdout + logError(err) return err }, SilenceUsage: true, diff --git a/cmd/init_test.go b/cmd/init_test.go index d7738fb63..063e67f4e 100644 --- a/cmd/init_test.go +++ b/cmd/init_test.go @@ -1,8 +1,11 @@ package commands import ( + "bytes" "os" + "os/exec" + dir "github.com/SAP/cloud-mta-build-tool/internal/archive" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -24,18 +27,170 @@ var _ = Describe("Init", func() { }) var _ = Describe("Build", func() { - BeforeEach(func() { - Ω(os.MkdirAll(getTestPath("result"), os.ModePerm)).Should(Succeed()) + mbtCmdCLI = getBuildCmdCli() }) AfterEach(func() { - Ω(os.RemoveAll(getTestPath("result"))).Should(Succeed()) + mbtCmdCLI = "" + }) + It("Success - build with abs source parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + }) + It("Success - build with relative source parameter", func() { + // Notice: relative source path is relative to os.Getwd() + source := "\"" + "testdata/mta" + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + }) + It("Success - build with abs source and abs target parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + target := "\"" + getTestPath("mtar_result") + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mtar_result"))).Should(Succeed()) + }) + It("Success - build with abs source and relative target path parameter", func() { + // Notice: target parameter is relative to source parameter + source := "\"" + getTestPath("mta") + "\"" + target := "\"" + "mtar_result" + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) }) - It("Failure - wrong platform", func() { - buildCmdSrc = getTestPath("mta") - buildCmdTrg = getTestPath("result") - buildCmdPlatform = "xxx" - err := buildCmd.RunE(nil, []string{}) - Ω(err).Should(HaveOccurred()) + It("Success - build with relative source and abs target path parameter", func() { + source := "\"" + "testdata/mta" + "\"" + target := "\"" + getTestPath("mta", "mtar_result") + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) + }) + It("Success - build with relative source and relative target path parameter", func() { + // Notice: target parameter is relative to source parameter + source := "\"" + "testdata/mta" + "\"" + target := "\"" + "mtar_result" + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) + }) + It("Failure - build with invalid source parameter case 1", func() { + // Notice: target parameter is relative to source parameter + source := "\"" + "testdata/**??mta" + "\"" + target := "\"" + "mtar_result" + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + // Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) + }) + It("Failure - build with invalid source parameter case 2", func() { + // Notice: target parameter is relative to source parameter + source := "\"" + "testdata<>/tmp" + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) + }) + It("Failure - build with invalid target parameter case 2", func() { + // Notice: target parameter is relative to source parameter + source := "\"" + "testdata/mta" + "\"" + target := "\"" + "mtar_result/??*tmp" + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --target "+target) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "mtar_result"))).Should(Succeed()) + }) */ + It("Success - build with relative sbom-file-path parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - build with abs sbom-file-path parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - build without mta.yaml", func() { + source := "\"" + getTestPath("tmp") + "\"" + Ω(os.MkdirAll(getTestPath("tmp"), os.ModePerm)).Should(Succeed()) + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("tmp"))).Should(Succeed()) + }) + It("Failure - build with invalid platform parameter", func() { + platform := "\"" + "xxx" + "\"" + source := "\"" + getTestPath("mta") + "\"" + + var stdout bytes.Buffer + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --platform "+platform) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) }) }) diff --git a/cmd/sbom.go b/cmd/sbom.go new file mode 100644 index 000000000..72daa3ffe --- /dev/null +++ b/cmd/sbom.go @@ -0,0 +1,67 @@ +package commands + +import ( + "os" + + "github.com/SAP/cloud-mta-build-tool/internal/artifacts" + "github.com/spf13/cobra" +) + +var projectSBomGenCmdSrc string +var projectSBomGenCmdSBOMPath string + +var moduleSBomGenCmdSrc string +var moduleSBomGenCmdModules []string +var moduleSBomGenCmdAllDependencies bool +var moduleSBomGenCmdSBOMPath string + +// Generate SBOM file for project +var projectSBomGenCommand = &cobra.Command{ + Use: "sbom-gen", + Short: "(beta) Generates SBOM for project according to configurations in the MTA development descriptor (mta.yaml)", + Long: "(beta) Generates SBOM for project according to configurations in the MTA development descriptor (mta.yaml)", + Args: cobra.MaximumNArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + err := artifacts.ExecuteProjectSBomGenerate(projectSBomGenCmdSrc, projectSBomGenCmdSBOMPath, os.Getwd) + // output err info to stdout + logError(err) + return err + }, + // Hidden: true, + SilenceUsage: true, +} + +// Generate SBOM file for modules +var moduleSBomGenCommand = &cobra.Command{ + Use: "module-sbom-gen", + Short: "Generates SBOM for specified modules according to configurations in the MTA development descriptor (mta.yaml)", + Long: "Generates SBOM for specified modules according to configurations in the MTA development descriptor (mta.yaml)", + Args: cobra.MaximumNArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + err := artifacts.ExecuteModuleSBomGenerate(moduleSBomGenCmdSrc, moduleSBomGenCmdModules, moduleSBomGenCmdAllDependencies, moduleSBomGenCmdSBOMPath, os.Getwd) + logError(err) + return err + }, + // Hidden: true, + SilenceUsage: true, + SilenceErrors: true, +} + +func init() { + + // set flags of sbom-gen command + projectSBomGenCommand.Flags().StringVarP(&projectSBomGenCmdSrc, "source", "s", "", + "The path of MTA project; project root path is set as default") + projectSBomGenCommand.Flags().StringVarP(&projectSBomGenCmdSBOMPath, "sbom-file-path", "b", "", + `The path of SBOM file, relative or absoluted; if relative path, it is relative to MTA project root; default value is /.bom.xml.`) + + // set flags of module-sbom-gen command + moduleSBomGenCommand.Flags().StringVarP(&moduleSBomGenCmdSrc, "source", "s", "", + "The path to the MTA project; the current path is set as default") + moduleSBomGenCommand.Flags().StringSliceVarP(&moduleSBomGenCmdModules, "modules", "m", nil, + "The names of the modules") + moduleSBomGenCommand.Flags().BoolVarP(&moduleSBomGenCmdAllDependencies, "with-all-dependencies", "a", true, + "Build modules including all dependencies") + moduleSBomGenCommand.Flags().StringVarP(&moduleSBomGenCmdSBOMPath, "sbom-file-path", "b", "", + `The path of SBOM file, relative or absoluted; if relative path, it is relative to MTA project root; default value is /.bom.xml.`) +} diff --git a/cmd/sbom_test.go b/cmd/sbom_test.go new file mode 100644 index 000000000..39855b885 --- /dev/null +++ b/cmd/sbom_test.go @@ -0,0 +1,422 @@ +package commands + +import ( + "bytes" + "os" + "os/exec" + "path/filepath" + + dir "github.com/SAP/cloud-mta-build-tool/internal/archive" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("mbt cli build and sbom gen", func() { + BeforeEach(func() { + mbtCmdCLI = getBuildCmdCli() + }) + + AfterEach(func() { + mbtCmdCLI = "" + buildCmdSrc = "" + buildCmdTrg = "" + buildCmdPlatform = "" + buildCmdKeepMakefile = false + }) + It("Success - build and gen sbom with relatvie source and relative sbom-file-path parameter", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + + var stdout bytes.Buffer + // cmd := exec.Command("bash", "-c", " mbt build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(Succeed()) + + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - build and gen sbom with abs source and relative sbom-file-path parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - build and gen sbom with relatvie source and abs sbom-file-path parameter", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - build and gen sbom with abs source and abs sbom-file-path parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - build and gen sbom with abs source and relative sbom-file-path paramerter with sbom file under project root", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "merged.bom.xml"))).Should(Succeed()) + }) + It("Success - build and gen sbom with relative source and relative sbom-file-path paramerter with sbom file under project root", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "merged.bom.xml"))).Should(Succeed()) + }) + It("Success - build and gen sbom without sbom-file-path parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + }) + It("Failure - build and gen sbom without mta.yaml", func() { + source := "\"" + getTestPath("tmp") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + Ω(os.MkdirAll(getTestPath("tmp"), os.ModePerm)).Should(Succeed()) + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("tmp"))).Should(Succeed()) + }) + It("Success - build without suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result_without_suffix") + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - build with json suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result.json") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(stdout.String()).Should(ContainSubstring("sbom file type .json is not supported at present")) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - build with unknow suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result.unknow") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(stdout.String()).Should(ContainSubstring("sbom file type .unknow is not supported at present")) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + /* It("Failure - build and gen sbom with invalid sbom-file-path parameter case 1", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "sbom-gen-result>>?/merged.bom.xml" + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - build and gen sbom with invalid sbom-file-path parameter case 2", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/**??merged.bom.xml" + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" build"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + // Notice: the merge sbom file name is invalid, the error will raised from cyclondx-cli merge command + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) */ +}) + +var _ = Describe("mbt cli sbom-gen", func() { + BeforeEach(func() { + mbtCmdCLI = getBuildCmdCli() + }) + + AfterEach(func() { + mbtCmdCLI = "" + buildCmdSrc = "" + buildCmdTrg = "" + buildCmdPlatform = "" + buildCmdKeepMakefile = false + }) + + It("Success - sbom-gen with abs source and without sbom-file-path paramerter", func() { + source := "\"" + getTestPath("mta") + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and without sbom-file-path paramerter", func() { + source := "\"" + "testdata/mta" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with abs source and relative sbom-file-path paramerter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with abs source and relative sbom-file-path paramerter with sbom file under project root", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + "merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "merged.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with abs source and abs sbom-file-path paramerter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and relative sbom-file-path paramerter", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and relative sbom-file-path paramerter with sbom file under project root", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "merged.bom.xml" + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "merged.bom.xml"))).Should(Succeed()) + }) + + It("Success - sbom-gen with relative source and abs sbom-file-path paramerter", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen without mta.yaml", func() { + source := "\"" + getTestPath("tmp") + "\"" + sbom_file_path := "\"" + "sbom-gen-result/merged.bom.xml" + "\"" + Ω(os.MkdirAll(getTestPath("tmp"), os.ModePerm)).Should(Succeed()) + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("tmp"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid source paramerter case 1", func() { + source := "\"" + "testdata??>/mta" + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid source paramerter case 2", func() { + source := "\"" + "testdata/***mta" + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "merged.bom.xml") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen without suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result_without_suffix") + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + + Ω(cmd.Run()).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with json suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result.json") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(stdout.String()).Should(ContainSubstring("sbom file type .json is not supported at present")) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with unknow suffix sbom-file-name parameter", func() { + source := "\"" + getTestPath("mta") + "\"" + sbom_file_path := "\"" + getTestPath("mta", "sbom-gen-result", "result.unknow") + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(stdout.String()).Should(ContainSubstring("sbom file type .unknow is not supported at present")) + Ω(os.RemoveAll(getTestPath("mta", dir.MtarFolder))).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + /* It("Failure - sbom-gen with invalid sbom-file-path paramerter case 1", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "sbom-gen-result??/merged.bom.xml" + "\"" + var stdout bytes.Buffer + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + cmd.Stdout = &stdout + Ω(cmd.Run()).Should(HaveOccurred()) + //Ω(stdout.String()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid sbom-file-path paramerter case 2", func() { + source := "\"" + "testdata/mta" + "\"" + sbom_file_path := "\"" + "sbom-gen-result/>>>merged.bom.xml" + "\"" + + cmd := exec.Command("bash", "-c", mbtCmdCLI+" sbom-gen"+" --source "+source+" --sbom-file-path "+sbom_file_path) + // Notice: the merge sbom file name is invalid, the error will raised from cyclondx-cli merge command + Ω(cmd.Run()).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) */ +}) + +var _ = Describe("project sbom gen command", func() { + BeforeEach(func() { + }) + + AfterEach(func() { + projectSBomGenCmdSrc = "" + projectSBomGenCmdSBOMPath = "" + }) + It("Success - sbom-gen with abs source and without sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = getTestPath("mta") + projectSBomGenCmdSBOMPath = "" + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(projectSBomGenCmdSrc, "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and without sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = "testdata/mta" + projectSBomGenCmdSBOMPath = "" + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(getTestPath("mta"), "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with abs source and relative sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = getTestPath("mta") + projectSBomGenCmdSBOMPath = "sbom-gen-result/merged.bom.xml" + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success -sbom-gen with abs source and abs sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = getTestPath("mta") + projectSBomGenCmdSBOMPath = filepath.Join(getTestPath("sbom-gen-result"), "merged.bom.xml") + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and relative sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = "testdata/mta" + projectSBomGenCmdSBOMPath = "sbom-gen-result/merged.bom.xml" + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "sbom-gen-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and abs sbom-file-path paramerter", func() { + projectSBomGenCmdSrc = "testdata/mta" + projectSBomGenCmdSBOMPath = filepath.Join(getTestPath("sbom-gen-result"), "merged.bom.xml") + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen without mta.yaml", func() { + tmpSrcFolder := getTestPath("tmp") + Ω(os.MkdirAll(tmpSrcFolder, os.ModePerm)).Should(Succeed()) + projectSBomGenCmdSrc = tmpSrcFolder + sbomFolderName := getTestPath("sbom-gen-result") + sbomFileName := "merged.bom.xml" + projectSBomGenCmdSBOMPath = filepath.Join(sbomFolderName, sbomFileName) + + Ω(projectSBomGenCommand.RunE(nil, []string{})).Should(HaveOccurred()) + Ω(os.RemoveAll(tmpSrcFolder)).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid source paramerter case 1", func() { + projectSBomGenCmdSrc = "testdata/>><>mta" + projectSBomGenCmdSBOMPath = filepath.Join(getTestPath("sbom-gen-result"), "merged.bom.xml") + + err := projectSBomGenCommand.RunE(nil, []string{}) + Ω(err).Should(HaveOccurred()) + //Ω(err.Error()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid source paramerter case 2", func() { + projectSBomGenCmdSrc = "testdata??/mta" + projectSBomGenCmdSBOMPath = filepath.Join(getTestPath("sbom-gen-result"), "merged.bom.xml") + + err := projectSBomGenCommand.RunE(nil, []string{}) + Ω(err).Should(HaveOccurred()) + //Ω(err.Error()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) + /* It("Failure - sbom-gen with invalid sbom-file-path paramerter case 1", func() { + projectSBomGenCmdSrc = "testdata/mta" + projectSBomGenCmdSBOMPath = "sbom-gen-result>>/merged.bom.xml" + + err := projectSBomGenCommand.RunE(nil, []string{}) + Ω(err).Should(HaveOccurred()) + //Ω(err.Error()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid sbom-file-path paramerter case 2", func() { + projectSBomGenCmdSrc = "testdata/mta" + projectSBomGenCmdSBOMPath = "sbom-gen-result/???merged.bom.xml" + err := projectSBomGenCommand.RunE(nil, []string{}) + // Notice: the merge sbom file name is invalid, the error will raised from cyclondx-cli merge command + Ω(err).Should(HaveOccurred()) + Ω(os.RemoveAll(getTestPath("sbom-gen-result"))).Should(Succeed()) + }) */ +}) diff --git a/cmd/testdata/mta-sbom/golang/go.mod b/cmd/testdata/mta-sbom/golang/go.mod new file mode 100644 index 000000000..2ed7e7e4d --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/go.mod @@ -0,0 +1,10 @@ +module github.com/cloudfoundry-samples/test-app + +go 1.13 + +require ( + github.com/bmizerany/pat v0.0.0-20140625234703-b8a35001b773 // indirect + github.com/pivotal-golang/lager v0.0.0-20150428205713-c88fa6d6c4d2 + github.com/tedsuo/ifrit v0.0.0-20150410161953-65ca48cd8a94 + github.com/tedsuo/rata v0.0.0-20141210191936-6197c97c67a0 +) diff --git a/cmd/testdata/mta-sbom/golang/go.sum b/cmd/testdata/mta-sbom/golang/go.sum new file mode 100644 index 000000000..ef81e956f --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/go.sum @@ -0,0 +1,204 @@ +github.com/CycloneDX/cyclonedx-go v0.6.0 h1:SizWGbZzFTC/O/1yh072XQBMxfvsoWqd//oKCIyzFyE= +github.com/CycloneDX/cyclonedx-go v0.6.0/go.mod h1:nQCiF4Tvrg5Ieu8qPhYMvzPGMu5I7fANZkrSsJjl5mg= +github.com/CycloneDX/cyclonedx-gomod v1.3.0 h1:G0xsizLbyOOmx/p6d3nx4IMMaqv9/ASOGIZOSk+fcpU= +github.com/CycloneDX/cyclonedx-gomod v1.3.0/go.mod h1:jqduZLsVxeYIrJFansmvH86sR9qrGSdl0T+MPhSLzrw= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bmizerany/pat v0.0.0-20140625234703-b8a35001b773 h1:u92n4d/2otMkjVmGnxLPUkl/P+eOKqcgxREHWl/2/6Y= +github.com/bmizerany/pat v0.0.0-20140625234703-b8a35001b773/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/bradleyjkemp/cupaloy/v2 v2.7.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= +github.com/dgryski/go-minhash v0.0.0-20170608043002-7fe510aff544 h1:54Y/2GF52MSJ4n63HWvNDFRtztgm6tq2UrOX61sjGKc= +github.com/dgryski/go-minhash v0.0.0-20170608043002-7fe510aff544/go.mod h1:VBi0XHpFy0xiMySf6YpVbRqrupW4RprJ5QTyN+XvGSM= +github.com/dgryski/go-spooky v0.0.0-20170606183049-ed3d087f40e2/go.mod h1:hgHYKsoIw7S/hlWtP7wD1wZ7SX1jPTtKko5X9jrOgPQ= +github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1 h1:/7G7q8SDJdrah5jDYqZI8pGFjSqiCzfSEO+NgqKCYX0= +github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1/go.mod h1:yEtCVi+QamvzjEH4U/m6ZGkALIkF2xfQnFp0BcKmIOk= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-enry/go-license-detector/v4 v4.3.0 h1:OFlQAVNw5FlKUjX4OuW8JOabu8MQHjTKDb9pdeNYMUw= +github.com/go-enry/go-license-detector/v4 v4.3.0/go.mod h1:HaM4wdNxSlz/9Gw0uVOKSQS5JVFqf2Pk8xUPEn6bldI= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hhatto/gorst v0.0.0-20181029133204-ca9f730cac5b h1:Jdu2tbAxkRouSILp2EbposIb8h4gO+2QuZEn3d9sKAc= +github.com/hhatto/gorst v0.0.0-20181029133204-ca9f730cac5b/go.mod h1:HmaZGXHdSwQh1jnUlBGN2BeEYOHACLVGzYOXCbsLvxY= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jdkato/prose v1.1.0 h1:LpvmDGwbKGTgdCH3a8VJL56sr7p/wOFPw/R4lM4PfFg= +github.com/jdkato/prose v1.1.0/go.mod h1:jkF0lkxaX5PFSlk9l4Gh9Y+T57TqUZziWT7uZbW5ADg= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jteeuwen/go-bindata v3.0.8-0.20180305030458-6025e8de665b+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb h1:bsjNADsjHq0gjU7KO7zwoX5k3HtFdf6TDzB3ncl5iUs= +github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/neurosnap/sentences v1.0.6/go.mod h1:pg1IapvYpWCJJm/Etxeh0+gtMf1rI1STY9S7eUCPbDc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24= +github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/pivotal-golang/lager v0.0.0-20150428205713-c88fa6d6c4d2 h1:5mfs0yZ4ijQYZr5DDwhwbzjAEqdbvFOoePnDg3w+erU= +github.com/pivotal-golang/lager v0.0.0-20150428205713-c88fa6d6c4d2/go.mod h1:EJZBAWMz/TvxVfLaBRwCv+gszrSByWbqQBRwfVbUhvM= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shogo82148/go-shuffle v0.0.0-20170808115208-59829097ff3b h1:VI1u+o2KZPZ5AhuPpXY0JBdpQPnkTx6Dd5XJhK/9MYE= +github.com/shogo82148/go-shuffle v0.0.0-20170808115208-59829097ff3b/go.mod h1:2htx6lmL0NGLHlO8ZCf+lQBGBHIbEujyywxJArf+2Yc= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tedsuo/ifrit v0.0.0-20150410161953-65ca48cd8a94 h1:cUXeV5OpVoN3ZAVGqz7oqFR0Bek2Hi5REtAtVeu7vOI= +github.com/tedsuo/ifrit v0.0.0-20150410161953-65ca48cd8a94/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= +github.com/tedsuo/rata v0.0.0-20141210191936-6197c97c67a0 h1:mdzr5v22IVdKf9mYBo0ate/vDWAes0RhuL/G8NNussw= +github.com/tedsuo/rata v0.0.0-20141210191936-6197c97c67a0/go.mod h1:X47ELzhOoLbfFIY0Cql9P6yo3Cdwf2CMX3FVZxRzJPc= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw= +gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/neurosnap/sentences.v1 v1.0.6 h1:v7ElyP020iEZQONyLld3fHILHWOPs+ntzuQTNPkul8E= +gopkg.in/neurosnap/sentences.v1 v1.0.6/go.mod h1:YlK+SN+fLQZj+kY3r8DkGDhDr91+S3JmTb5LSxFRQo0= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/cmd/testdata/mta-sbom/golang/handlers/assets.go b/cmd/testdata/mta-sbom/golang/handlers/assets.go new file mode 100644 index 000000000..163b2d232 --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/assets.go @@ -0,0 +1,124 @@ +package handlers + +import "text/template" + +var styledTemplate = template.Must(template.New("experiment").Parse(` + + + + + +{{.Body}} + + +`)) + +type Body struct { + Body string + Class string +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/env.go b/cmd/testdata/mta-sbom/golang/handlers/env.go new file mode 100644 index 000000000..f4197be9f --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/env.go @@ -0,0 +1,31 @@ +package handlers + +import ( + "encoding/json" + "net/http" + "os" + "strings" +) + +type Env struct { +} + +func (p *Env) ServeHTTP(w http.ResponseWriter, r *http.Request) { + formatJson := r.URL.Query().Get("json") + if formatJson == "" { + out := "
" + for _, env := range os.Environ() { + kv := strings.Split(env, "=") + out += "
" + kv[0] + "
" + out += "
" + kv[1] + "
" + } + out += "
" + styledTemplate.Execute(w, Body{Body: `
` + out + `
`}) + } else { + envs := [][]string{} + for _, env := range os.Environ() { + envs = append(envs, strings.Split(env, "=")) + } + json.NewEncoder(w).Encode(envs) + } +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/exit.go b/cmd/testdata/mta-sbom/golang/handlers/exit.go new file mode 100644 index 000000000..54e0bccdd --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/exit.go @@ -0,0 +1,40 @@ +package handlers + +import ( + "fmt" + "net/http" + "os" + "time" + + "github.com/cloudfoundry-samples/test-app/helpers" +) + +type Exit struct { + Time time.Time +} + +func (p *Exit) ServeHTTP(w http.ResponseWriter, r *http.Request) { + index, _ := helpers.FetchIndex() + + w.WriteHeader(http.StatusOK) + styledTemplate.Execute(w, Body{ + Class: "goodbye", + Body: fmt.Sprintf(` +
+ Shutting Down +
+ +
My Index Is
+ +
%d
+
Uptime: %s
+
+ `, index, time.Since(p.Time)), + }) + + go func() { + time.Sleep(100 * time.Millisecond) + fmt.Println("Test App shutting down") + os.Exit(1) + }() +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/handlers.go b/cmd/testdata/mta-sbom/golang/handlers/handlers.go new file mode 100644 index 000000000..164f1f82d --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/handlers.go @@ -0,0 +1,46 @@ +package handlers + +import ( + "net/http" + "time" + + "github.com/cloudfoundry-samples/test-app/routes" + "github.com/pivotal-golang/lager" + "github.com/tedsuo/rata" +) + +func New(logger lager.Logger, port string) rata.Handlers { + t := time.Now() + handlers := rata.Handlers{ + routes.Env: &Env{}, + routes.Hello: &Hello{Time: t}, + routes.Exit: &Exit{Time: t}, + routes.Index: &Index{}, + routes.Port: &Port{ + Port: port, + }, + } + + for route, handler := range handlers { + handlers[route] = &LoggingHandler{ + Route: route, + Handler: handler, + Logger: logger, + } + } + + return handlers +} + +type LoggingHandler struct { + Route string + Handler http.Handler + Logger lager.Logger +} + +func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + session := h.Logger.Session(h.Route) + session.Debug("request.begin") + h.Handler.ServeHTTP(w, r) + session.Debug("request.end") +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/hello.go b/cmd/testdata/mta-sbom/golang/handlers/hello.go new file mode 100644 index 000000000..dcd557dbf --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/hello.go @@ -0,0 +1,29 @@ +package handlers + +import ( + "fmt" + "net/http" + "time" + + "github.com/cloudfoundry-samples/test-app/helpers" +) + +type Hello struct { + Time time.Time +} + +func (p *Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) { + index, _ := helpers.FetchIndex() + + styledTemplate.Execute(w, Body{Body: fmt.Sprintf(` +
+ Test App +
+ +
My Index Is
+ +
%d
+
Uptime: %s
+
+ `, index, time.Since(p.Time))}) +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/index.go b/cmd/testdata/mta-sbom/golang/handlers/index.go new file mode 100644 index 000000000..869b9ca1f --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/index.go @@ -0,0 +1,21 @@ +package handlers + +import ( + "fmt" + "net/http" + + "github.com/cloudfoundry-samples/test-app/helpers" +) + +type Index struct { +} + +func (_ *Index) ServeHTTP(w http.ResponseWriter, r *http.Request) { + index, err := helpers.FetchIndex() + + if err != nil { + w.Write([]byte(err.Error())) + } + + w.Write([]byte(fmt.Sprintf("%d", index))) +} diff --git a/cmd/testdata/mta-sbom/golang/handlers/port.go b/cmd/testdata/mta-sbom/golang/handlers/port.go new file mode 100644 index 000000000..9ba3c5734 --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/handlers/port.go @@ -0,0 +1,14 @@ +package handlers + +import ( + "fmt" + "net/http" +) + +type Port struct { + Port string +} + +func (p *Port) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(fmt.Sprintf("%s", p.Port))) +} diff --git a/cmd/testdata/mta-sbom/golang/helpers/fetch_index.go b/cmd/testdata/mta-sbom/golang/helpers/fetch_index.go new file mode 100644 index 000000000..0c3ba3da1 --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/helpers/fetch_index.go @@ -0,0 +1,17 @@ +package helpers + +import ( + "os" + "strconv" +) + +func FetchIndex() (int, error) { + index := "-1" + + if os.Getenv("CF_INSTANCE_INDEX") != "" { + index = os.Getenv("CF_INSTANCE_INDEX") + } else if os.Getenv("INSTANCE_INDEX") != "" { + index = os.Getenv("INSTANCE_INDEX") + } + return strconv.Atoi(index) +} diff --git a/cmd/testdata/mta-sbom/golang/main.go b/cmd/testdata/mta-sbom/golang/main.go new file mode 100644 index 000000000..19f1e89d0 --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/main.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/cloudfoundry-samples/test-app/handlers" + "github.com/cloudfoundry-samples/test-app/helpers" + "github.com/cloudfoundry-samples/test-app/routes" + "github.com/pivotal-golang/lager" + "github.com/tedsuo/ifrit" + "github.com/tedsuo/ifrit/http_server" + "github.com/tedsuo/rata" +) + +var message string +var quiet bool + +var portsFlag = flag.String( + "ports", + "", + "Comma delimited list of ports, where the app will be listening to", +) + +func init() { + flag.StringVar(&message, "message", "Hello", "The Message to Log and Display") + flag.BoolVar(&quiet, "quiet", false, "Less Verbose Logging") + flag.Parse() +} + +func main() { + flag.Parse() + + logger := lager.NewLogger("test-app") + if quiet { + logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO)) + } else { + logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.DEBUG)) + } + + ports := getServerPorts() + + logger.Info("test-app.starting", lager.Data{"ports": ports}) + index, err := helpers.FetchIndex() + appName := fetchAppName() + go func() { + t := time.NewTicker(time.Second) + for { + <-t.C + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fetch index: %s\n", err.Error()) + } else { + fmt.Println(fmt.Sprintf("%s. Says %s. on index: %d", appName, message, index)) + } + } + }() + + wg := sync.WaitGroup{} + for _, port := range ports { + wg.Add(1) + go func(wg *sync.WaitGroup, port string) { + defer wg.Done() + handler, err := rata.NewRouter(routes.Routes, handlers.New(logger, port)) + if err != nil { + logger.Fatal("router.creation.failed", err) + } + + server := ifrit.Envoke(http_server.New(":"+port, handler)) + logger.Info("test-app.up", lager.Data{"port": port}) + err = <-server.Wait() + if err != nil { + logger.Error("shutting down server", err, lager.Data{"server port": port}) + } + logger.Info("shutting down server", lager.Data{"server port": port}) + }(&wg, port) + } + wg.Wait() + logger.Info("shutting latice app") +} + +func fetchAppName() string { + appName := os.Getenv("APP_NAME") + if appName == "" { + return "test-app" + } + return appName +} + +func getServerPorts() []string { + givenPorts := *portsFlag + if givenPorts == "" { + givenPorts = os.Getenv("PORT") + } + if givenPorts == "" { + givenPorts = "8080" + } + ports := strings.Replace(givenPorts, " ", "", -1) + return strings.Split(ports, ",") +} diff --git a/cmd/testdata/mta-sbom/golang/routes/routes.go b/cmd/testdata/mta-sbom/golang/routes/routes.go new file mode 100644 index 000000000..46d5f9e6f --- /dev/null +++ b/cmd/testdata/mta-sbom/golang/routes/routes.go @@ -0,0 +1,19 @@ +package routes + +import "github.com/tedsuo/rata" + +const ( + Env = "ENV" + Hello = "HELLO" + Exit = "EXIT" + Index = "INDEX" + Port = "PORT" +) + +var Routes = rata.Routes{ + {Path: "/", Method: "GET", Name: Hello}, + {Path: "/env", Method: "GET", Name: Env}, + {Path: "/exit", Method: "GET", Name: Exit}, + {Path: "/index", Method: "GET", Name: Index}, + {Path: "/port", Method: "GET", Name: Port}, +} diff --git a/cmd/testdata/mta-sbom/java/package-lock.json b/cmd/testdata/mta-sbom/java/package-lock.json new file mode 100644 index 000000000..5d0c8c801 --- /dev/null +++ b/cmd/testdata/mta-sbom/java/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "java-test-case", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/cmd/testdata/mta-sbom/java/pom.xml b/cmd/testdata/mta-sbom/java/pom.xml new file mode 100644 index 000000000..3d3f432f0 --- /dev/null +++ b/cmd/testdata/mta-sbom/java/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + com.sap.mta.example + com.sap.mta.example.backend + 0.0.1-SNAPSHOT + war + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + javax.servlet + jsp-api + 2.0 + provided + + + + backend + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + + + \ No newline at end of file diff --git a/cmd/testdata/mta-sbom/java/src/main/java/com/sap/mta/example/Backend.java b/cmd/testdata/mta-sbom/java/src/main/java/com/sap/mta/example/Backend.java new file mode 100644 index 000000000..16b9f7b86 --- /dev/null +++ b/cmd/testdata/mta-sbom/java/src/main/java/com/sap/mta/example/Backend.java @@ -0,0 +1,20 @@ + +import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet({"/backend"}) +public class Backend + extends HttpServlet +{ + private static final long serialVersionUID = 1L; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + response.getWriter().append("BLUE").flush(); + } +} diff --git a/cmd/testdata/mta-sbom/java/src/main/webapp/WEB-INF/web.xml b/cmd/testdata/mta-sbom/java/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..6fb367fa5 --- /dev/null +++ b/cmd/testdata/mta-sbom/java/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,12 @@ + + + com.sap.mta.example.backend + + index.html + index.htm + index.jsp + default.html + default.htm + default.jsp + + \ No newline at end of file diff --git a/cmd/testdata/mta-sbom/mta.yaml b/cmd/testdata/mta-sbom/mta.yaml new file mode 100644 index 000000000..3846d6748 --- /dev/null +++ b/cmd/testdata/mta-sbom/mta.yaml @@ -0,0 +1,46 @@ +ID: mta_sbom_test_app +_schema-version: '2.1' +version: 0.0.1 + +modules: +- name: node-module + type: nodejs + path: nodejs + provides: + - name: node-js_api + properties: + url: ${default-url} + build-parameters: + requires: + - name: java-module + +- name: java-module + type: java + path: java + properties: + MEMORY_CALCULATOR_V1: true + build-parameters: + requires: + - name: go-module + +- name: go-module + type: go + path: golang + parameters: + memory: 512M + disk-quota: 256M + properties: + MEMORY_CALCULATOR_V1: true + build-parameters: + builder: golang + requires: + - name: custom-module + +- name: custom-module + type: html5 + path: nodejs + build-parameters: + builder: custom + commands: + - sh -c 'echo customer builder' + diff --git a/cmd/testdata/mta-sbom/nodejs/node-js/gulpfile.js b/cmd/testdata/mta-sbom/nodejs/node-js/gulpfile.js new file mode 100644 index 000000000..4d1b56cdc --- /dev/null +++ b/cmd/testdata/mta-sbom/nodejs/node-js/gulpfile.js @@ -0,0 +1,132 @@ +/** + * This is the gulp script to run jasmine tests with coverage analysis using istanbul. + * For more information, please see also: + * @see {@link http://jasmine.github.io/2.0/introduction.html} + * @see {@link https://www.npmjs.com/package/istanbul} + * @see {@link https://www.npmjs.com/package/gulp} + * @see {@link https://www.npmjs.com/package/gulp-istanbul} + * @see {@link https://www.npmjs.com/package/gulp-jasmine} + * @see {@link https://www.npmjs.com/package/jasmine-reporters} + * @see {@link https://www.npmjs.com/package/glob} + **/ + +var path = require("path"); + +var gulp = require("gulp"); +var jasmine = require("gulp-jasmine"); +var istanbul = require("gulp-istanbul"); +var reporters = require("jasmine-reporters"); + +// required to replace absolute paths in results with relative ones +var replace = require("gulp-replace"); + +// configuration of the test coverage, uses glob syntax +// @see {@link https://www.npmjs.com/package/glob} + +// the following files are included in the coverage analysis +// include all javascript files and exclude myExclude.js +// replace or remove files depending on what is to be excluded or included in addition +var includedScripts = ["**/*.js", "!myExclude.js"]; + +// the following files are part of the framework and are to be excluded from the test coverage +var defaultExclusion = ["!**/*spec.js", "!rungulp.js", "!gulpfile.js", "!**/node_modules/**", "!appcontroller.*/**", "!vendor/**"]; + +// test results folder for test view history +// assign each test run a unique timestamp, coverage and test results +// are associated via timestamp, so the test results folder fills up with files +// of form: +// 123456_report.xml +// 123456_coverage.json +// 456789_report.xml +// 456789_coverage.json +// ... +var testResultsDir = path.join(__dirname, ".testresults"); + +var timestamp = Date.now(); +var testResultFile = timestamp + "_report.xml"; +var coverageResultFile = timestamp + "_coverage.json"; + +/** + * Instrument the test/productive code + */ +gulp.task("instrumentation", function() { + return gulp.src(includedScripts.concat(defaultExclusion)) + // Covering files + .pipe(istanbul({ + includeUntested: true // instrument all files + })) + // Force `require` to return covered files + .pipe(istanbul.hookRequire()); +}); + +/** + * Execute tests with coverage information, requires instrumentation + * before tests are executed + */ +gulp.task("jasmine-istanbul", ["instrumentation"], function() { + // run all tests ending with "spec", skip all tests that are part of the node_modules + return gulp.src(["**/*spec.js", "!**/node_modules/**"]) + .pipe(jasmine({ + errorOnFail: false, + // use the standard junit xml reporter + reporter: new reporters.JUnitXmlReporter({ + savePath: testResultsDir, + filePrefix: testResultFile, + consolidateAll: true + }) + })) + .pipe(istanbul.writeReports({ + // generage json report for the coverage + reporters: ["json"], + reportOpts: { + json: { + dir: testResultsDir, + file: coverageResultFile + } + } + })); +}); + +/** + * Execute tests without coverage information + */ +gulp.task("jasmine", function() { + // run all tests ending with "spec", skip all tests that are part of the node_modules + return gulp.src(["**/*spec.js", "!**/node_modules/**"]) + .pipe(jasmine({ + errorOnFail: false, + // use the standard junit xml reporter + reporter: new reporters.JUnitXmlReporter({ + savePath: testResultsDir, + filePrefix: testResultFile, + consolidateAll: true + }) + })); +}); + +/** + * Remove absolute path portions so test view can open the referenced files + */ +function postProcessing() { + return gulp.src([ + path.join(testResultsDir, testResultFile), + path.join(testResultsDir, coverageResultFile) + ], { + dot: true + }) + .pipe(replace(__dirname, "")) + .pipe(gulp.dest(testResultsDir)); +} + +// run tests with coverage analysis +gulp.task("test-coverage", ["jasmine-istanbul"], function() { + return postProcessing(); +}); + +// only run the tests, skip test coverage analysis +gulp.task("test", ["jasmine"], function() { + return postProcessing(); +}); + +//the default task is to run tests with coverage analysis +gulp.task("default", ["test-coverage"]); diff --git a/cmd/testdata/mta-sbom/nodejs/node-js/package.json b/cmd/testdata/mta-sbom/nodejs/node-js/package.json new file mode 100644 index 000000000..e063e00a1 --- /dev/null +++ b/cmd/testdata/mta-sbom/nodejs/node-js/package.json @@ -0,0 +1,24 @@ +{ + "dependencies": { + "prune": "0.0.2" + }, + "devDependencies": { + "gulp": "3.9.1", + "gulp-replace": "0.5.4", + "jasmine-reporters": "2.1.1", + "gulp-jasmine": "2.4.1", + "gulp-istanbul": "1.1.1" + }, + "files": [], + "main": "server.js", + "name": "node-js", + "scripts": { + "start": "node server.js", + "test": "node ./node_modules/gulp/bin/gulp test", + "test-coverage": "node ./node_modules/gulp/bin/gulp test-coverage" + }, + "engines": { + "node": ">=14.15.0" + }, + "version": "1.0.0" +} diff --git a/cmd/testdata/mta-sbom/nodejs/node-js/server.js b/cmd/testdata/mta-sbom/nodejs/node-js/server.js new file mode 100644 index 000000000..07fabe2ec --- /dev/null +++ b/cmd/testdata/mta-sbom/nodejs/node-js/server.js @@ -0,0 +1,12 @@ +/*eslint no-console: 0*/ +"use strict"; + +var http = require("http"); +var port = process.env.PORT || 3000; + +http.createServer(function (req, res) { + res.writeHead(200, {"Content-Type": "text/plain"}); + res.end("Hello World\n"); +}).listen(port); + +console.log("Server listening on port %d", port); diff --git a/cmd/testdata/mta-sbom/nodejs/package-lock.json b/cmd/testdata/mta-sbom/nodejs/package-lock.json new file mode 100644 index 000000000..d1a22937d --- /dev/null +++ b/cmd/testdata/mta-sbom/nodejs/package-lock.json @@ -0,0 +1,292 @@ +{ + "name": "mta", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "mta", + "version": "1.0.0", + "dependencies": { + "mongodb": "*" + } + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/bson": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/bson/-/bson-5.2.0.tgz", + "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==", + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/mongodb": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.2.0.tgz", + "integrity": "sha512-nLgo95eP1acvjBcOdrUV3aqpWwHZCZwhYA2opB8StybbtQL/WoE5pk92qUUfjbKOWcGLYJczTqQbfOQhYtrkKg==", + "dependencies": { + "bson": "^5.2.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "saslprep": "^1.0.3" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.201.0", + "mongodb-client-encryption": "^2.3.0", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "bson": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/bson/-/bson-5.2.0.tgz", + "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==" + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "mongodb": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.2.0.tgz", + "integrity": "sha512-nLgo95eP1acvjBcOdrUV3aqpWwHZCZwhYA2opB8StybbtQL/WoE5pk92qUUfjbKOWcGLYJczTqQbfOQhYtrkKg==", + "requires": { + "bson": "^5.2.0", + "mongodb-connection-string-url": "^2.6.0", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + } + } +} diff --git a/cmd/testdata/mta-sbom/nodejs/package.json b/cmd/testdata/mta-sbom/nodejs/package.json new file mode 100644 index 000000000..83ac52ad0 --- /dev/null +++ b/cmd/testdata/mta-sbom/nodejs/package.json @@ -0,0 +1,7 @@ +{ + "name": "mta", + "version": "1.0.0", + "dependencies": { + "mongodb": "*" + } +} diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index da89b95fd..0f45d7761 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -1,5 +1,5 @@ -###Overview +### Overview Optionally, you can define the builder behavior by configuring the parameters in the `build-parameters` section in the `mta.yaml` file for each module or globally. @@ -60,6 +60,7 @@ modules: > **_CAUTION:_** Cyclical dependencies are not allowed. If such dependencies are found, the build fails.
+ ##### Using build results for building another module If you want to use the build results of module B for building module A, modify the `requires` section as follows: @@ -268,6 +269,7 @@ For example: ``` Also, you can use this parameter to define timeout for the [global `before-all` build](configuration.md#configuring-global-build). + #### Configuring the build artifact name The module build results are by default packaged into the resulting archive under the name “data”. You can change this name as needed using the `build-artifact-name` build parameter:     @@ -291,7 +293,7 @@ modules:   -#### Configuring a module that does not have source code to build and package +#### Configuring a module that does not have source code to build and package (BETA) There are use cases when a module does not have any source code that should be built and therefore there are no build results to be packaged into the MTA archive. The module definition in the MTA descriptor is the only input that is required to deploy the module into the target environment. You can instruct the tool to treat the module as such by setting the build parameter `no-source` to `true` as follows: @@ -308,4 +310,82 @@ modules: ``` When the `no-source` parameter is `true`, the tool does not validate the `path` property, so it can be omitted as shown in the example above. No action is performed during the module's build step, so all parameters configuring the module build behaviour, e.g. `builder`, `timeout`, `ignore`, etc. are ignored. There is no content associated with this module in the result MTA archive. The rest of the module processing is the same as when the parameter is not provided, e.g. the entry in the generated the deployment descriptor is created based on `supported-platforms` settings. +#### Configuring a module that needs to generate SBOM content +Three native builders, `npm, maven, and golang`, have been upgraded to support Software Bill of Materials (SBOM) generation. + +Set `build-parameters.builder` attribute value to `npm, maven or golang`: + +```yaml +modules: + - name: node-module + type: nodejs + path: nodejs + provides: + - name: node-js_api + properties: + url: ${default-url} + build-parameters: + builder: npm + requires: + - name: java-module + +- name: java-module + type: java + path: java + properties: + MEMORY_CALCULATOR_V1: true + build-parameters: + builder: maven + requires: + - name: go-module + +- name: go-module + type: go + path: golang + parameters: + memory: 512M + disk-quota: 256M + properties: + MEMORY_CALCULATOR_V1: true + build-parameters: + builder: golang + requires: + - name: custom-module + +mbt build --sbom-file-path sbom-path/test.sbom.xml + +or + +mbt sbom-gen --sbom-file-path sbom-path/test.sbom.xml +``` +For the `java` or `nodejs` module types, since their default builder is `maven` or `npm`, you do not need to set the `build-parameters.builder` attribute: + +```yaml +modules: + - name: node-module + type: nodejs + path: nodejs + provides: + - name: node-js_api + properties: + url: ${default-url} + build-parameters: + requires: + - name: java-module + +- name: java-module + type: java + path: java + properties: + MEMORY_CALCULATOR_V1: true + build-parameters: + requires: + - name: go-module + +mbt build --sbom-file-path sbom-path/test.sbom.xml + +or + +mbt sbom-gen --sbom-file-path sbom-path/test.sbom.xml +```   diff --git a/docs/docs/sbom-tools.md b/docs/docs/sbom-tools.md new file mode 100644 index 000000000..665c51ea9 --- /dev/null +++ b/docs/docs/sbom-tools.md @@ -0,0 +1,40 @@ +For Software Bill of Materials (SBOM) file generation, some SBOM tools are required to be installed in your environment: + +#### Install CycloneDX Gomod +[cyclonedx-gomod](https://github.com/CycloneDX/cyclonedx-gomod) creates CycloneDX Software Bill of Materials (SBOM) from Go modules. + +Run the following command to install CycloneDX Gomod: + +```yaml +curl -fsSLO --compressed https://github.com/CycloneDX/cyclonedx-gomod/releases/download/v1.4.1/cyclonedx-gomod_1.4.0_linux_amd64.tar.gz + +tar -xzf cyclonedx-gomod_1.4.0_linux_amd64.tar.gz + +chmod a+rx cyclonedx-gomod + +mv cyclonedx-gomod /usr/local/bin/cyclonedx-gomod +``` + +#### Install the CycloneDX Node Module +[cyclonedx-node-module](https://github.com/eoftedal/cyclonedx-node-module) creates CycloneDX BOMs from Node.js projects. + +Run the following command to install the CycloneDX Node Module: + +```yaml +npm install -g cyclonedx-bom +``` + +#### Install the CycloneDX CLI +The [CycloneDX CLI tool](https://github.com/CycloneDX/cyclonedx-cli) currently supports BOM analysis, modification, diffing, merging, format conversion, signing, and verification. + +Run the following command to install the CycloneDX CLI tool: + +```yaml +curl -fsSLO --compressed https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.24.2/cyclonedx-linux-x64 + +chmod a+rx cyclonedx-linux-x64 + +mv cyclonedx-linux-x64 /usr/local/bin/cyclonedx +``` + + diff --git a/docs/docs/usage.md b/docs/docs/usage.md index a5e9036c2..770274a28 100644 --- a/docs/docs/usage.md +++ b/docs/docs/usage.md @@ -61,6 +61,7 @@ Generates a temporary `Makefile` according to the MTA descriptor and runs the `m | `--strict` | Optional | The default value is `true`. If set to `true`, the duplicated fields and fields that are not defined in the `mta.yaml` schema are reported as errors. If set to `false`, they are reported as warnings. | `mbt build -p=cf --strict=true` | BETA   `-m (--mode)` | Optional | The possible value is `verbose`. If run with this option, the temporary `Makefile` is generated in a way that allows the parallel execution of `Make` jobs to make the build process faster. | `mbt build -m=verbose` | BETA   `-j (--jobs)` | Optional | Used only with the `--mode` parameter. This option configures the number of `Make` jobs that can run simultaneously. If omitted or if the value is less than or equal to zero, the number of jobs is defined by the number of available CPUs (maximum 8). | `mbt build -m=verbose -j=8` +| BETA   `-b (--sbom-file-path)` | Optional | The path of the SBOM file. The last part of the path is the file name.
  • If the sbom-file-path is null, the SBOM file will not be generated.
  • The sbom-file-path can be relative or abs; If the path is relative, it is the relative path to the project root.
  • Only an XML file format is currently supported, so if the file suffix is .xml, or if there's no file suffix, an XML format SBOM will be generated.
| `mbt build --sbom-file-path sbom-gen/test.sbom.xml`   @@ -119,9 +120,6 @@ Packages the MTA project into the MTA archive according to the `Makefile`. ### How to build an MTA archive from the modules' build artifacts - - - `mbt assemble` Creates an MTA archive `MTAR` file from the module build artifacts according to the MTA deployment descriptor (`mtad.yaml` file). @@ -181,3 +179,19 @@ Triggers the build process of the specified module according to the implicit or | `-g (--mtad-gen)` | Optional | If the parameter is provided, the deployment descriptor `mtad.yaml` is generated by default in the current folder or in the folder configured by the `--target` parameter.
A module's `path` property in the generated `mtad.yaml` file points to the module's build results if this module was selected using the `--modules` option.

Notes:
  • The selected module list specified using the `--module` option, does not affect the list of modules in the resulting `mtad.yaml` file. The `mtad.yaml` file is always generated according to the default Cloud MTA Builder settings, the `build-parameters` configurations in the `mta.yaml` file (e.g. `supported-platforms`), and the selected target platform.
  • By default, the `mtad.yaml` is generated for the `cf` target platform. You can configure a different target plaform using the `--platform` option. | `mbt module-build -m=my_module1,my_module2 -g` | `-p (--platform)` | Optional | The name of the target deployment platform. Used only with the `-g (--mtad-gen)` parameter.
    The supported deployment platforms are:
    • `cf` for SAP Cloud Platform, Cloud Foundry environment
    • `neo` for the SAP Cloud Platform, Neo environment
    • `xsa` for the SAP HANA XS advanced model
    If this parameter is not provided, the `mtad.yaml` file is generated for the SAP Cloud Platform, Cloud Foundry environment. | `mbt module-build -m=my_module1,my_module2 -g -p=neo` + +  + +### How to generate an SBOM file from the project source (BETA) + +`mbt sbom-gen` +This command generates SBOMs for project modules and merges the SBOMs into one, according to configurations in the MTA development descriptor ('mta.yaml' file). + +Usage: `mbt sbom-gen ` + +Flags: + +| Flag | Mandatory /
    Optional | Description                           | Examples                      +| ----------- | ------- | ---------- | ----------------------------- +| `-s (--source)` | Optional | The path to the MTA project; the current path is set as the default. | `mbt sbom-gen -s C:/TestProject -b sbom-file-gen/test.sbom.xml` +| `-b (--sbom-file-path)` | Optional | The path of the SBOM file. The last part of the path is the file name.
    • The sbom-file-path can be null. If the sbom-file-path is null, the default value is /.bom.xml.
    • The sbom-file-path can be relative or abs; If the path is relative, it is the relative path to the project root.
    • The sbom-file-path's last part is the file name.
    • Only the XML file format is currently supported; So, if the file suffix is .xml, or if there's no file suffix, an XML format SBOM will be generated.
    | `mbt sbom-gen --sbom-file-path sbom-gen/test.sbom.xml` \ No newline at end of file diff --git a/docs/docs/whatsnew.md b/docs/docs/whatsnew.md index f03a82d2b..29ca1a492 100644 --- a/docs/docs/whatsnew.md +++ b/docs/docs/whatsnew.md @@ -1,5 +1,20 @@ # Important updates +## v1.2.26 + +### Support SBOM generation (BETA) +The Software Bill of Materials (SBOM) is a list of components, libraries, and module information that are required to build a software, and the supply chain relationships between them. An SBOM also lists the licenses that govern those components, versions of the components used in the codebase, and their patch status. + +With SBOM, teams can quickly identify any associated security or license risks of codebase. + +The `npm, maven, and golang` native builders and the `mbt build, mbt sbom-gen` commands have been upgraded to support SBOM generation. For `java or nodejs` module types, or if the module's `build-parameters.builder` attribute value is `npm, maven, or golang`, SBOM content will be generated and merged into one file. Currently, only the XML format SBOM file is supported. + +The module configuration can be referenced in the [configuration.md](https://github.com/SAP/cloud-mta-build-tool/blob/master/docs/docs/configuration.md) file. + +The SBOM generation commands `mbt build` and `mbt sbom-gen` can be referenced in the [usage.md](https://github.com/SAP/cloud-mta-build-tool/blob/master/docs/docs/usage.md) file. + +Some SBOM tools are required to be installed in your environment, they can be referenced in the [sbom-tools.md](https://github.com/SAP/cloud-mta-build-tool/blob/master/docs/docs/sbom-tools.md) file. + ## v1.2.25 ### Configuration of `maven` builder has changed. diff --git a/integration/cloud_mta_build_tool_test.go b/integration/cloud_mta_build_tool_test.go index 1d550eb73..c3abcdac2 100644 --- a/integration/cloud_mta_build_tool_test.go +++ b/integration/cloud_mta_build_tool_test.go @@ -32,25 +32,16 @@ const ( binPath = "mbt" ) -var _ = Describe("Integration - CloudMtaBuildTool", func() { +var mbtName = "" +var mbtTargetPath = "" - var mbtName = "" +var _ = Describe("Integration - CloudMtaBuildTool", func() { BeforeSuite(func() { - By("Building MBT") - if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { - mbtName = "mbt" - } else { - mbtName = "mbt.exe" - } - // This runs locally for testing purpose only - /* #nosec */ - cmd := exec.Command("go", "build", "-o", filepath.Join(os.Getenv("GOPATH"), "/bin/"+mbtName), ".") - cmd.Dir = filepath.FromSlash("../") - err := cmd.Run() - if err != nil { - fmt.Println("binary creation failed: ", err) - } + By("Building and smoke testing mbt") + mbtName = "mbt" + buildAndInstallMBT() + smokeTestMBT() }) AfterSuite(func() { @@ -660,6 +651,38 @@ resources: }) }) +func buildAndInstallMBT() error { + if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { + mbtName = mbtName + } else { + mbtName = mbtName + ".exe" + } + mbtTargetPath = filepath.Join(os.Getenv("GOPATH"), "/bin/"+mbtName) + + cmd := exec.Command("go", "build", "-o", mbtTargetPath, ".") + cmd.Dir = filepath.FromSlash("../") + err := cmd.Run() + if err != nil { + fmt.Println("mbt build and install failed: ", err) + return err + } + + return nil +} + +func smokeTestMBT() error { + var stdout bytes.Buffer + cmd := exec.Command(mbtName, "-h") + cmd.Stdout = &stdout + err := cmd.Run() + if err != nil { + fmt.Println("exec mbt -h error: ", err) + return err + } + fmt.Println("exec mbt -h success: ", stdout.String()) + return nil +} + func getFileContentFromZip(path string, filename string) ([]byte, error) { zipFile, err := zip.OpenReader(path) if err != nil { diff --git a/internal/archive/fsops.go b/internal/archive/fsops.go index 3f0057b2f..aa2a1baae 100755 --- a/internal/archive/fsops.go +++ b/internal/archive/fsops.go @@ -2,6 +2,7 @@ package dir import ( "archive/zip" + "fmt" "io" "io/ioutil" "os" @@ -53,6 +54,16 @@ func CreateDirIfNotExist(dir string) error { return err } +// RemoveDirIfExist - remove dir +func RemoveIfExist(dir string) error { + _, err := os.Stat(dir) + if os.IsNotExist(err) { + return nil + } + err = os.RemoveAll(dir) + return err +} + // Archive module and mtar artifacts, // compatible with the JAR specification // to support the spec requirements @@ -392,6 +403,27 @@ func FindPath(path string) (string, error) { return "", errors.Errorf(wrongPathMsg, path) } +func FindFile(root string, filename string) (string, error) { + var foundPath string + err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && info.Name() == filename { + foundPath = path + return filepath.SkipDir + } + return nil + }) + if err != nil { + return "", err + } + if foundPath == "" { + return "", fmt.Errorf("%s not found in %s", filename, root) + } + return foundPath, nil +} + // CopyByPatterns - copy files/directories according to patterns // from source folder to target folder // patterns are relative to source folder @@ -621,6 +653,7 @@ func changeTargetMode(source, target string) error { if err != nil { return err } + return os.Chmod(target, si.Mode()) } diff --git a/internal/archive/mta_location.go b/internal/archive/mta_location.go index 38fff48e9..235f1030e 100644 --- a/internal/archive/mta_location.go +++ b/internal/archive/mta_location.go @@ -21,6 +21,8 @@ const ( Mtad = "mtad.yaml" // MtarFolder - default archives folder MtarFolder = "mta_archives" + // SBomTempFolderSuffix - sbom temporary folder suffix + SBomTempFolderSuffix = "_mta_sbom_tmp" ) // IMtaParser - MTA Parser interface @@ -212,6 +214,13 @@ func (ep *Loc) GetManifestPath() string { return filepath.Join(ep.GetMetaPath(), "MANIFEST.MF") } +// GetSBomFileTmpDir - sbomFileTmpDir is a temp folder under project root +func (ep *Loc) GetSBomFileTmpDir(mtaObj *mta.MTA) string { + source := ep.GetSource() + sbomtmpdir := "." + mtaObj.ID + SBomTempFolderSuffix + return filepath.Join(source, sbomtmpdir) +} + // ValidateDeploymentDescriptor validates the deployment descriptor. func ValidateDeploymentDescriptor(descriptor string) error { if descriptor != "" && descriptor != Dev && descriptor != Dep { @@ -242,7 +251,6 @@ func (ep *Loc) GetExtensionFilePaths() []string { // Location - provides Location parameters of MTA func Location(source, target, descriptor string, extensions []string, wdGetter func() (string, error)) (*Loc, error) { - err := ValidateDeploymentDescriptor(descriptor) if err != nil { return nil, err diff --git a/internal/artifacts/artifacts_msg.go b/internal/artifacts/artifacts_msg.go index e5ad8a209..085d28427 100644 --- a/internal/artifacts/artifacts_msg.go +++ b/internal/artifacts/artifacts_msg.go @@ -88,4 +88,16 @@ const ( mergeInfoMsg = `merging the "mta.yaml" file with the MTA extension descriptors...` mergeNameRequiredMsg = `could not find the mandatory parameter "target-file-name"` mergeFailedOnFileCreationMsg = `the "%s" file already exists` + + genSBomFileStartMsg = `start to generate sbom file` + genSBomFileFinishedMsg = `finish generate sbom file %s` + genSBomForModuleStartMsg = `start to generate sbom for module %s` + genSBomForModuleFinishMsg = `finish generate sbom for module %s` + genSBomSkipModuleMsg = `skip module %s sbom generation, mbt is not support it by now` + genSBomEmptyMsg = `sbom file %s will not be generated, mbt is not supporte generate sbom for all modules of the application` + genSBomFileMergingMsg = `merging sbom file %s` + genSBomFileFailedMsg = `generate sbom file failed` + createSBomTargetDirFailedMsg = `create sbom file target path "%s" failed` + mvSBomToTargetDirFailedMsg = `mv sbom file from "%s" to "%s" failed` + genSBomNotSupportedFileTypeMsg = `sbom file type %s is not supported at present` ) diff --git a/internal/artifacts/project.go b/internal/artifacts/project.go index 215374c8d..7cdc98125 100644 --- a/internal/artifacts/project.go +++ b/internal/artifacts/project.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" - "github.com/SAP/cloud-mta-build-tool/internal/archive" + dir "github.com/SAP/cloud-mta-build-tool/internal/archive" "github.com/SAP/cloud-mta-build-tool/internal/commands" "github.com/SAP/cloud-mta-build-tool/internal/exec" "github.com/SAP/cloud-mta-build-tool/internal/logs" @@ -25,40 +25,55 @@ const ( ) // ExecBuild - Execute MTA project build -func ExecBuild(makefileTmp, source, target string, extensions []string, mode, mtar, platform string, strict bool, jobs int, outputSync bool, wdGetter func() (string, error), wdExec func([][]string, bool) error, useDefaultMbt bool, keepMakefile bool) error { +func ExecBuild(makefileTmp, source, target string, extensions []string, mode, mtar, platform string, + strict bool, jobs int, outputSync bool, wdGetter func() (string, error), wdExec func([][]string, bool) error, + useDefaultMbt bool, keepMakefile bool, sBomFilePath string) error { message, err := version.GetVersionMessage() if err == nil { logs.Logger.Info(message) } - // Generate build script + // (1) generate build script err = tpl.ExecuteMake(source, "", extensions, makefileTmp, mode, wdGetter, useDefaultMbt) if err != nil { return err } - cmdParams := createMakeCommand(makefileTmp, source, target, mode, mtar, platform, strict, jobs, outputSync, runtime.NumCPU) - err = wdExec([][]string{cmdParams}, false) + // (2) execute make command + cmdParams := createMakeCommand(makefileTmp, source, target, mode, mtar, platform, strict, jobs, + outputSync, runtime.NumCPU) + execMakeFileError := wdExec([][]string{cmdParams}, false) - // Remove temporary Makefile - var removeError error = nil + // (3) remove temporary Makefile + var removeMakeFileError error = nil if !keepMakefile { - removeError = os.Remove(filepath.Join(source, filepath.FromSlash(makefileTmp))) - if removeError != nil { - removeError = errors.Wrapf(removeError, removeFailedMsg, makefileTmp) + removeMakeFileError = os.Remove(filepath.Join(source, filepath.FromSlash(makefileTmp))) + if removeMakeFileError != nil { + removeMakeFileError = errors.Wrapf(removeMakeFileError, removeFailedMsg, makefileTmp) } } - if err != nil { - if removeError != nil { - logs.Logger.Error(removeError) + if execMakeFileError != nil { + if removeMakeFileError != nil { + logs.Logger.Error(removeMakeFileError) } - return errors.Wrap(err, execFailedMsg) + return errors.Wrap(execMakeFileError, execFailedMsg) + } + + if removeMakeFileError != nil { + return removeMakeFileError } - return removeError + + // (4) generate sbom file + sBomGenError := ExecuteProjectBuildeSBomGenerate(source, sBomFilePath, wdGetter) + if sBomGenError != nil { + return errors.Wrap(sBomGenError, execFailedMsg) + } + return nil } -func createMakeCommand(makefileName, source, target, mode, mtar, platform string, strict bool, jobs int, outputSync bool, numCPUGetter func() int) []string { +func createMakeCommand(makefileName, source, target, mode, mtar, platform string, strict bool, jobs int, + outputSync bool, numCPUGetter func() int) []string { cmdParams := []string{source, "make", "-f", makefileName, "p=" + platform, "mtar=" + mtar, "strict=" + strconv.FormatBool(strict), "mode=" + mode} if target != "" { cmdParams = append(cmdParams, `t="`+target+`"`) diff --git a/internal/artifacts/project_test.go b/internal/artifacts/project_test.go index 785daef5d..f8447eae5 100644 --- a/internal/artifacts/project_test.go +++ b/internal/artifacts/project_test.go @@ -11,7 +11,7 @@ import ( . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" - "github.com/SAP/cloud-mta-build-tool/internal/archive" + dir "github.com/SAP/cloud-mta-build-tool/internal/archive" "github.com/SAP/cloud-mta-build-tool/internal/commands" "github.com/SAP/cloud-mta-build-tool/internal/exec" "github.com/SAP/cloud-mta/mta" @@ -57,21 +57,21 @@ var _ = Describe("Project", func() { It("Sanity", func() { err := ExecBuild("Makefile_tmp.mta", getTestPath("mta_with_zipped_module"), getResultPath(), nil, "", "", "cf", true, 0, false, os.Getwd, func(strings [][]string, b bool) error { return nil - }, true, false) + }, true, false, "") Ω(err).Should(Succeed()) Ω(filepath.Join(getTestPath("mta_with_zipped_module"), "Makefile_tmp.mta")).ShouldNot(BeAnExistingFile()) }) It("Sanity - keep makefile", func() { err := ExecBuild("Makefile_tmp.mta", getTestPath("mta_with_zipped_module"), getResultPath(), nil, "", "", "cf", true, 0, false, os.Getwd, func(strings [][]string, b bool) error { return nil - }, true, true) + }, true, true, "") Ω(err).Should(Succeed()) Ω(filepath.Join(getTestPath("mta_with_zipped_module"), "Makefile_tmp.mta")).Should(BeAnExistingFile()) }) It("Wrong - no platform", func() { err := ExecBuild("Makefile_tmp.mta", getTestPath("mta_with_zipped_module"), getResultPath(), nil, "", "", "", true, 0, false, os.Getwd, func(strings [][]string, b bool) error { return fmt.Errorf("failure") - }, true, false) + }, true, false, "") Ω(err).Should(HaveOccurred()) }) It("Wrong - ExecuteMake fails on wrong location", func() { @@ -80,7 +80,7 @@ var _ = Describe("Project", func() { return "", errors.New("wrong location") }, func(strings [][]string, b bool) error { return nil - }, true, false) + }, true, false, "") Ω(err).Should(HaveOccurred()) }) }) diff --git a/internal/artifacts/sbom.go b/internal/artifacts/sbom.go new file mode 100644 index 000000000..e6252ed51 --- /dev/null +++ b/internal/artifacts/sbom.go @@ -0,0 +1,363 @@ +package artifacts + +import ( + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + dir "github.com/SAP/cloud-mta-build-tool/internal/archive" + "github.com/SAP/cloud-mta-build-tool/internal/buildops" + "github.com/SAP/cloud-mta-build-tool/internal/commands" + "github.com/SAP/cloud-mta-build-tool/internal/exec" + "github.com/SAP/cloud-mta-build-tool/internal/logs" + "github.com/SAP/cloud-mta-build-tool/internal/version" + "github.com/SAP/cloud-mta/mta" + "github.com/pkg/errors" +) + +const ( + xml_type = "xml" + json_type = "json" + unsupport_type = "unsupport_sbom_type" + xml_suffix = ".xml" + json_suffix = ".json" + sbom_xml_suffix = ".bom.xml" + sbom_json_suffix = ".bom.json" + cyclonedx_cli = "cyclonedx" +) + +// ExecuteProjectSBomGenerate - Execute MTA project SBOM generation +func ExecuteProjectSBomGenerate(source string, sbomFilePath string, wdGetter func() (string, error)) error { + // (1) get loc object and mta object + loc, err := dir.Location(source, "", dir.Dev, []string{}, wdGetter) + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + mtaObj, err := loc.ParseFile() + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + // (2) if sbom file path is empty, default value is /.bom.xml + if strings.TrimSpace(sbomFilePath) == "" { + sbomFilePath = mtaObj.ID + sbom_xml_suffix + } + + // (3) generate sbom + err = executeSBomGenerate(loc, mtaObj, source, sbomFilePath) + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + return nil +} + +// ExecuteProjectBuildeSBomGenerate - Execute MTA project SBOM generation with Build process +func ExecuteProjectBuildeSBomGenerate(source string, sbomFilePath string, wdGetter func() (string, error)) error { + // (1) if sbomFilePath is empty, do not need to generate sbom, return directly + if strings.TrimSpace(sbomFilePath) == "" { + return nil + } + + // (2) get loc object and mta object + loc, err := dir.Location(source, "", dir.Dev, []string{}, wdGetter) + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + mtaObj, err := loc.ParseFile() + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + // (3) generate sbom + err = executeSBomGenerate(loc, mtaObj, source, sbomFilePath) + if err != nil { + return errors.Wrapf(err, genSBomFileFailedMsg) + } + + return nil +} + +// prepareEnv - create sbom tmp dir and sbom target dir +// Notice: must not remove the sbom target dir, if the sbom-file is generated under project root, remove sbom path will delete app +func prepareEnv(sbomTmpDir, sbomPath string) error { + err := dir.RemoveIfExist(sbomTmpDir) + if err != nil { + return err + } + err = dir.CreateDirIfNotExist(sbomTmpDir) + if err != nil { + return err + } + err = dir.CreateDirIfNotExist(sbomPath) + if err != nil { + return err + } + + return nil +} + +// cleanEnv - clean sbom tmp dir +func cleanEnv(sbomTmpDir string) error { + err := dir.RemoveIfExist(sbomTmpDir) + if err != nil { + return err + } + return nil +} + +// generateSBomFile - generate all modules sbom and merge in to one, then mv it to sbom target path +func generateSBomFile(loc *dir.Loc, mtaObj *mta.MTA, + sbomPath, sbomName, sbomType, sbomSuffix, sbomTmpDir string) error { + // (1) generation sbom for modules under sbom tmp dir + err := generateSBomFiles(loc, mtaObj, sbomTmpDir, sbomType, sbomSuffix) + if err != nil { + return err + } + + // (2) list all generated module sbom file in tmp + sbomFileNames, err := listSBomFilesInTmpDir(sbomTmpDir, sbomSuffix) + if err != nil { + return err + } + // if sbom tmp dir is empty, maybe all modules are unknow builder or custom builders + if len(sbomFileNames) == 0 { + logs.Logger.Infof(genSBomEmptyMsg, sbomName) + return nil + } + + // (3) merge sbom files under sbom tmp dir + sbomTmpName, err := mergeSBomFiles(loc, sbomTmpDir, sbomFileNames, sbomName, sbomType, sbomSuffix) + if err != nil { + return err + } + + // (4) generate sbom target dir, mv merged sbom file to target dir + err = moveSBomToTarget(sbomPath, sbomName, sbomTmpDir, sbomTmpName) + if err != nil { + return err + } + + return nil +} + +func executeSBomGenerate(loc *dir.Loc, mtaObj *mta.MTA, source string, sbomFilePath string) error { + // start generate sbom file log + logs.Logger.Info(genSBomFileStartMsg) + + // (1) parse sbomFilePath, if relative, it is relative path to project source + // json type sbom file is not supported at present, if sbom file type is json, return not support error + sbomPath, sbomName, sbomType, sbomSuffix := parseSBomFilePath(loc.GetSource(), sbomFilePath) + if sbomType == unsupport_type { + return errors.Errorf(genSBomNotSupportedFileTypeMsg, sbomSuffix) + } + + // (2) create sbom tmp dir and sbom target path + sbomTmpDir := loc.GetSBomFileTmpDir(mtaObj) + prepareErr := prepareEnv(sbomTmpDir, sbomPath) + if prepareErr != nil { + return prepareErr + } + + // (3) generate sbom file + genError := generateSBomFile(loc, mtaObj, sbomPath, sbomName, sbomType, sbomSuffix, sbomTmpDir) + if genError != nil { + cleanErr := cleanEnv(sbomTmpDir) + if cleanErr != nil { + logs.Logger.Error(cleanErr) + } + return genError + } + + // (4) clean sbom tmp dir + cleanErr := cleanEnv(sbomTmpDir) + if cleanErr != nil { + return cleanErr + } + + // finish generate sbom file log + logs.Logger.Infof(genSBomFileFinishedMsg, sbomName) + + return nil +} + +// moveSBomToTarget - move sbom file from sbom tmp dir to target dir +func moveSBomToTarget(sbomPath string, sbomName string, sbomTmpDir string, sbomTmpName string) error { + err := dir.CreateDirIfNotExist(sbomPath) + if err != nil { + return errors.Wrapf(err, createSBomTargetDirFailedMsg, sbomName) + } + + sourcesbomfilepath := filepath.Join(sbomTmpDir, sbomTmpName) + targetsbomfilepath := filepath.Join(sbomPath, sbomName) + + err = os.Rename(sourcesbomfilepath, targetsbomfilepath) + if err != nil { + return errors.Wrapf(err, mvSBomToTargetDirFailedMsg, sourcesbomfilepath, targetsbomfilepath) + } + return nil +} + +// listSBomFilesInTmpDir - list generated sbom files for modules +// if sbom tmp dir is empty, return empty array +func listSBomFilesInTmpDir(sbomTmpDir, sbomSuffix string) ([]string, error) { + var sbomFileNames []string + fileInfos, err := ioutil.ReadDir(sbomTmpDir) + if err != nil { + return sbomFileNames, err + } + + for _, file := range fileInfos { + fileName := file.Name() + if !file.IsDir() && len(fileName) > 0 && strings.HasSuffix(fileName, sbomSuffix) { + sbomFileNames = append(sbomFileNames, fileName) + } + } + return sbomFileNames, nil +} + +// mergeSBomFiles - merge sbom files of modules under sbom tmp dir +func mergeSBomFiles(loc *dir.Loc, sbomTmpDir string, sbomFileNames []string, sbomName, sbomType, sbomSuffix string) (string, error) { + curtime := time.Now().Format("20230328150313") + + var sbomTmpName string + if strings.HasSuffix(sbomName, sbom_xml_suffix) { + sbomTmpName = strings.TrimSuffix(sbomName, xml_suffix) + "_" + curtime + sbom_xml_suffix + } else if strings.HasSuffix(sbomName, sbom_json_suffix) { + sbomTmpName = strings.TrimSuffix(sbomName, json_suffix) + "_" + curtime + sbom_json_suffix + } else { + sbomTmpName = sbomName + "_" + curtime + sbom_xml_suffix + } + + // get sbom file generate command + sbomMergeCmds, err := commands.GetSBomsMergeCommand(loc, cyclonedx_cli, sbomTmpDir, sbomFileNames, sbomTmpName, sbomType, sbomSuffix) + if err != nil { + return "", err + } + + // merging sbom file log + logs.Logger.Infof(genSBomFileMergingMsg, sbomName) + + // exec sbom merge command + err = executeSBomCommand(sbomMergeCmds) + if err != nil { + return "", err + } + return sbomTmpName, nil +} + +// parseSBomFilePath - parse sbom file path parameter +// if sbom file path is a relative path, join source path +// only xml file format is supported at present; +func parseSBomFilePath(source string, sbomFilePath string) (string, string, string, string) { + var sbomPath, sbomName, sbomType, sbomSuffix string + + if filepath.IsAbs(sbomFilePath) { + sbomPath, sbomName = filepath.Split(sbomFilePath) + } else { + sbomPath, sbomName = filepath.Split(filepath.Join(source, sbomFilePath)) + } + + // if file suffix is .xml, or no file suffix, xml format type will be return + // if file suffix is not .xml, unsupported file type will be return + fileSuffix := filepath.Ext(sbomName) + if fileSuffix == "" || strings.HasSuffix(sbomName, xml_suffix) { + sbomType = xml_type + sbomSuffix = sbom_xml_suffix + } else { + sbomType = unsupport_type + sbomSuffix = fileSuffix + } + + return sbomPath, sbomName, sbomType, sbomSuffix +} + +func executeSBomCommand(sbomCmds [][]string) error { + err := exec.ExecuteWithTimeout(sbomCmds, "", true) + if err != nil { + return err + } + return nil +} + +// generateSBomFiles - loop all mta modules and generate sbom for each of then +// if module's builder is custom, skip it +func generateSBomFiles(loc *dir.Loc, mtaObj *mta.MTA, sBomFileTmpDir string, sbomType string, sbomSuffix string) error { + // (1) sort module by dependency orders + sortedModuleNames, err := buildops.GetModulesNames(mtaObj) + if err != nil { + return err + } + + // (2) loop modules to generate sbom files + curtime := time.Now().Format("20230328150313") + for _, moduleName := range sortedModuleNames { + // start generate module sbom log + logs.Logger.Infof(genSBomForModuleStartMsg, moduleName) + + module, err := mtaObj.GetModuleByName(moduleName) + if err != nil { + return err + } + + sbomFileName := moduleName + "_" + curtime + sbomFileFullName := sbomFileName + sbomSuffix + + // get sbom file generate command + sbomGenCmds, err := commands.GetModuleSBomGenCommands(loc, module, sbomFileName, sbomType, sbomSuffix) + if err != nil { + return err + } + // if sbomGenCmds is empty, module builder maybe "custom" or unknow builder, skip the module and continue + if len(sbomGenCmds) == 0 { + logs.Logger.Infof(genSBomSkipModuleMsg, moduleName) + continue + } + + // exec sbom generate command + err = executeSBomCommand(sbomGenCmds) + if err != nil { + return err + } + + // mv module sbom file to sbom temp dir + modulePath := loc.GetSourceModuleDir(module.Path) + sbomFileFoundPath, err := dir.FindFile(modulePath, sbomFileFullName) + if err != nil { + return err + } + sbomFileTargetPath := filepath.Join(sBomFileTmpDir, sbomFileFullName) + err = os.Rename(sbomFileFoundPath, sbomFileTargetPath) + if err != nil { + return err + } + + // finish generate module sbom log + logs.Logger.Infof(genSBomForModuleFinishMsg, moduleName) + } + + return nil +} + +// ExecuteModuleSBomGenerate - Execute specified modules of MTA project SBOM generation +func ExecuteModuleSBomGenerate(source string, modulesNames []string, allDependencies bool, sBomFilePath string, wdGetter func() (string, error)) error { + logs.Logger.Info("source: " + source) + + for _, moduleName := range modulesNames { + logs.Logger.Info("module: " + moduleName) + } + + logs.Logger.Info("allDependencies: " + strconv.FormatBool(allDependencies)) + logs.Logger.Info("sBomFilePath: " + sBomFilePath) + + message, err := version.GetVersionMessage() + if err == nil { + logs.Logger.Info(message) + } + return err +} diff --git a/internal/artifacts/sbom_test.go b/internal/artifacts/sbom_test.go new file mode 100644 index 000000000..a1852fe56 --- /dev/null +++ b/internal/artifacts/sbom_test.go @@ -0,0 +1,233 @@ +package artifacts + +import ( + "os" + "path/filepath" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("mbt sbom-gen command", func() { + BeforeEach(func() { + + }) + AfterEach(func() { + + }) + + It("Success - sbom-gen with abs source and without sbom-file-path paramerter", func() { + source := getTestPath("mta") + sbomFilePath := "" + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(getTestPath("mta"), "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and without sbom-file-path paramerter", func() { + source := "testdata/mta" + sbomFilePath := "" + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(getTestPath("mta"), "mta.bom.xml"))).Should(Succeed()) + }) + It("Success - sbom-gen with abs source and relative sbom-file-path paramerter", func() { + source := getTestPath("mta") + sbomFilePath := "gen-sbom-result/merged.bom.xml" + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(getTestPath("mta", "gen-sbom-result")))).Should(Succeed()) + + }) + It("Success - sbom-gen with abs source and abs sbom-file-path paramerter", func() { + source := getTestPath("mta") + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "merged.bom.xml") + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(filepath.Join(getTestPath("gen-sbom-result")))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and relative sbom-file-path paramerter", func() { + source := "testdata/mta" + sbomFilePath := "gen-sbom-result/merged.bom.xml" + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("mta", "gen-sbom-result"))).Should(Succeed()) + }) + It("Success - sbom-gen with relative source and abs sbom-file-path paramerter", func() { + source := "testdata/mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "merged.bom.xml") + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with invalid source paramerter case 1", func() { + source := "testdata??/mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "merged.bom.xml") + + err := ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd) + Ω(err).Should(HaveOccurred()) + //Ω(err.Error()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + + }) + It("Failure - sbom-gen with invalid source paramerter case 2", func() { + source := "testdata/*??>mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "merged.bom.xml") + + err := ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd) + Ω(err).Should(HaveOccurred()) + //Ω(err.Error()).Should(ContainSubstring("The filename, directory name, or volume label syntax is incorrect")) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + }) + It("Success - sbom-gen without suffix sbom-file-name paramerter", func() { + source := "testdata/mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "result_without_suffix") + Ω(ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd)).Should(Succeed()) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with json suffix sbom-file-name parameter", func() { + source := "testdata/mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "result.json") + + err := ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd) + Ω(err).Should(HaveOccurred()) + Ω(err.Error()).Should(ContainSubstring("sbom file type .json is not supported at present")) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + }) + It("Failure - sbom-gen with unknow suffix sbom-file-name parameter", func() { + source := "testdata/mta" + sbomFilePath := filepath.Join(getTestPath("gen-sbom-result"), "result.unknow") + + err := ExecuteProjectSBomGenerate(source, sbomFilePath, os.Getwd) + Ω(err).Should(HaveOccurred()) + Ω(err.Error()).Should(ContainSubstring("sbom file type .unknow is not supported at present")) + Ω(os.RemoveAll(getTestPath("gen-sbom-result"))).Should(Succeed()) + }) + /* It("Failure - sbom-gen with invalid sbom-file-path paramerter case 1", func() { + source := "testdata/mta" + sbomFilePath := "gen-sbom-result>>?