CI/CD mit SharePoint Framework, Teil 2

von Roland Rickborn
CI/CD mit SharePoint Framework

In dieser Blogpost-Serie beschreibe ich meine Vorstellung der idealen CI/CD-Pipeline einer Adaptive Card Extension (ACE) für Viva Connections mit Hilfe des SharePoint Frameworks (SPFx) und unter Verwendung von Dependency-Track für Continuous Transparency. Der erste Teil der Serie [1] befasste sich mit der automatisierten Aktualisierung von Abhängigkeiten. Im zweiten Teil geht es jetzt um die Verwaltung von Abhängigkeiten und die Auslieferung.

CI/CD bei SharePoint Framework mit Schwachstellen-Management

Mein Kollege hat in seinem Blogpost [2] bereits ausführlich die Vorteile eines SBOM-Management-Systems beschrieben. In unserem Fall kommt dafür die Anwendung Dependency-Track [3] zum Einsatz, die über eine umfangreiche REST API verfügt. Das Einbinden dieser Anwendung in eine GitLab Pipeline hat mein Kollege ebenfalls schon in einem Blogpost [4] vorgestellt. Abweichend von der dort vorgestellten Pipeline-Konfiguration erstelle ich im Schritt upload-sbom-job beim Upload der SBOM-Datei in meiner Pipeline kein neues Projekt, sondern aktualisiere das bestehende.

Das Projekt in Dependency-Track sieht so aus:

Das Projekt trägt das Label Application, hat keine Version und der tag Latest ist gesetzt.

Die Pipeline-Konfiguration des Schritts upload-sbom-job lautet:

upload-sbom-job:
  stage: upload
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  needs:
    - job: build-job
      artifacts: true
  image: curlimages/curl:8.18.0
  script:
    - |
      PROJECT_UUID=$(curl -s \
        -H "X-Api-Key: ${DTRACK_API_KEY}" \
        "${DTRACK_URL}/api/v1/project?name=$PROJECT_NAME&sortName=lastBomImport&sortOrder=desc&offset=0&limit=1" \
        | tr -d '\n' \
        | sed -n 's/.*"uuid":"\([^"]*\)".*/\1/p')
      echo "Found Project UUID: $PROJECT_UUID"
    - |
      curl -f -v POST "${DTRACK_URL}/api/v1/bom" \
      -H "X-Api-Key: ${DTRACK_API_KEY}" \
      -F "project=$PROJECT_UUID" \
      -F "autoCreate=$AUTO_CREATE" \
      -F "bom=@./$SBOM_FILE"

Continuous Transparency bei CI/CD mit SharePoint Framework

Unmittelbar nach Beendigung des Uploads der SBOM-Datei startet Dependency-Track mit der Analyse der in der SBOM-Datei genannten Pakete. Dieser Prozess dauert in der Regel nur wenige Sekunden. Im Schritt fetch-metrics-job meiner Pipeline habe ich dafür ein Zeitfenster von 30 Sekunden reserviert. Danach startet die Pipeline mit dem auslesen der Ergebnisse der Analyse von Dependency-Track. Denn ich möchte die ermittelten Werte sowohl direkt im Release in GitLab darstellen, als auch im Release-Bundle speichern. Die Konfiguration des Pipeline-Jobs ist:

fetch-metrics-job:
  stage: release
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  needs:
    - job: build-job
      artifacts: true
  image: curlimages/curl:8.18.0
  script:
    - export VERSION_NUMBER=$(cat VERSION)
    - sleep 30
    - |
      PROJECT_UUID=$(curl -s \
        -H "X-Api-Key: ${DTRACK_API_KEY}" \
        "${DTRACK_URL}/api/v1/project?name=$PROJECT_NAME&sortName=lastBomImport&sortOrder=desc&offset=0&limit=1" \
        | tr -d '\n' \
        | sed -n 's/.*"uuid":"\([^"]*\)".*/\1/p')
      echo "Found Project UUID: $PROJECT_UUID"
    - |
      curl -s \
        -H "X-Api-Key: ${DTRACK_API_KEY}" \
        "${DTRACK_URL}/api/v1/metrics/project/${PROJECT_UUID}/current" \
        > metrics.json
    - |
      get_num() {
        local key="$1"
        local val
        val=$(grep -o "\"${key}\":[0-9][0-9]*" metrics.json | head -n1 | cut -d: -f2)
        if [ -z "$val" ]; then echo 0; else echo "$val"; fi
      }
      INHERITED_RISK=$(grep -o '"inheritedRiskScore":[0-9]\+\(\.[0-9]\+\)\?' metrics.json | head -n1 | cut -d: -f2)
      [ -z "$INHERITED_RISK" ] && INHERITED_RISK=0
      VULN_CRITICAL=$(get_num critical)
      VULN_HIGH=$(get_num high)
      VULN_MEDIUM=$(get_num medium)
      VULN_LOW=$(get_num low)
      FINDINGS_TOTAL=$(get_num findingsTotal)
      FINDINGS_SUPPRESSED=$(get_num suppressed)
      POLICY_VIOLATIONS_FAIL=$(get_num policyViolationsFail)
      POLICY_VIOLATIONS_TOTAL=$(get_num policyViolationsTotal)
      {
        echo "PROJECT_UUID=${PROJECT_UUID}"
        echo "INHERITED_RISK=${INHERITED_RISK}"
        echo "VULN_CRITICAL=${VULN_CRITICAL}"
        echo "VULN_HIGH=${VULN_HIGH}"
        echo "VULN_MEDIUM=${VULN_MEDIUM}"
        echo "VULN_LOW=${VULN_LOW}"
        echo "FINDINGS_TOTAL=${FINDINGS_TOTAL}"
        echo "FINDINGS_SUPPRESSED=${FINDINGS_SUPPRESSED}"
        echo "POLICY_VIOLATIONS_FAIL=${POLICY_VIOLATIONS_FAIL}"
        echo "POLICY_VIOLATIONS_TOTAL=${POLICY_VIOLATIONS_TOTAL}"
        echo "VERSION_NUMBER=${VERSION_NUMBER}"
        echo "PROJECT_NAME=${PROJECT_NAME}"
      } > dtrack-metrics.env
  artifacts:
    paths:
      - dtrack-metrics.env
    reports:
      dotenv: dtrack-metrics.env
    expire_in: 14 days

Das dabei entstehende Artefakt dtrack-metrics.env ist eine leicht zu verarbeitende Datei, die alle relevanten Metriken des Projekts enthält.

Packaging bei CI/CD mit SharePoint Framework

Im nun folgenden Schritt package-artifacts-job werden alle bisher gesammelten Daten und erstellten Artefakte zu einem Release-Bundle, ein ZIP-Archiv, zusammengestellt. Die Konfiguration ist:

package-artifacts-job:
  stage: release
  image: alpine:3.23
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  needs:
    - job: build-job
      artifacts: true
    - job: upload-sbom-job
      artifacts: true
    - job: fetch-metrics-job
      artifacts: true
  script:
    - set -euo pipefail
    - apk add --no-cache zip
    - ZIP_NAME="release-bundle-v${VERSION_NUMBER}.zip"
    - echo "Creating ${ZIP_NAME}"
    - zip -j "$ZIP_NAME" dtrack-metrics.env VERSION "$SBOM_FILE" sharepoint/solution/hello-world.sppkg
    - ls -lh "$ZIP_NAME"
  artifacts:
    name: "release-bundle-v${CI_COMMIT_SHORT_SHA}"
    paths:
      - release-bundle-v*.zip
    expire_in: 14 days

Das in diesem Schritt entstandene Artefakt trägt in der aktuellen Pipeline den Namen release-bundle-v4.3.6.zip und enthält die Dateien:

  • dtrack-metrics.env
  • hello-world.sppkg
  • sbom-sharepoint-viva-connections.cdx.json und
  • VERSION

Dieser Schritt ist aus diesen zwei Gründen relevant für mich:

  1. Zum einen soll größtmögliche Transparenz hergestellt werden. Daher wird das Release-Bundle als separates Artefakt angeboten, das alle relevanten Informationen enthält.
  2. Außerdem dient dieses Vorgehen als Vorbereitung für eine CI/CD Pipeline beim Kunden, bei dem Software-Erstellung und -Bereitstellung organisatorisch getrennt ist.

Release bei CI/CD mit SharePoint Framework

GitLab bietet mit Releases [5] eine bequeme Möglichkeit, definierte Softwarestände inklusive Code, Artefakte und Dokumentation zu speichern und zu veröffentlichen. Dieses Feature verwende ich im Schritt release-job meiner Pipeline. Darin wird ein neues Release mit der aktuellen Versionsnummer angelegt. Die ausführliche Beschreibung des Releases enthält unter anderem die Metriken aus Dependency-Track. Außerdem findet sich darin ein direkter Link zum Release-Bundle, also dem ZIP-Archiv mit der Package-Datei. Die Konfiguration sieht so aus:

release-job:
  stage: release
  image: registry.gitlab.com/gitlab-org/cli:latest
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  needs:
    - job: package-artifacts-job
      artifacts: true
    - job: fetch-metrics-job
      artifacts: true
  script:
    - echo "Preparing release v${VERSION_NUMBER}"
    - echo "Risk score = ${INHERITED_RISK}"
    - echo "Vulnerabilities = C=${VULN_CRITICAL} H=${VULN_HIGH} M=${VULN_MEDIUM} L=${VULN_LOW}"
    - echo "Policy violations = (fail/total) ${POLICY_VIOLATIONS_FAIL}/${POLICY_VIOLATIONS_TOTAL}"
  release:
    tag_name: "v${VERSION_NUMBER}"
    name: "Release v${VERSION_NUMBER}"
    description: |
      # 🚀 **GeoLocation Test Release v${VERSION_NUMBER}**

      ## 🔐 Dependency-Track (metrics only)

      **Risk**
      - Inherited risk score: **${INHERITED_RISK}**

      **Vulnerabilities**
      - Critical: **${VULN_CRITICAL}**
      - High: **${VULN_HIGH}**
      - Medium: **${VULN_MEDIUM}**
      - Low: **${VULN_LOW}**

      **Findings**
      - Total findings: **${FINDINGS_TOTAL}**

      **Policy**
      - Violations (total): **${POLICY_VIOLATIONS_TOTAL}**
    assets:
      links:
        - name: "Full release bundle (ZIP)"
          url: "${CI_PROJECT_URL}/-/jobs/artifacts/${CI_COMMIT_REF_NAME}/raw/release-bundle-v${VERSION_NUMBER}.zip?job=package-artifacts-job"

Die daraus entstehende Release-Seite in GitLab sieht so aus:

Eigentlich würde an dieser Stelle der Pipeline der Schritt Deployment folgen. Für den Upload der Package-Datei in den SharePoint App-Katalog würde ich CLI for Microsoft 365 [6] in Verbindung mit zertifikat-basierter Authentifizierung einsetzen. Im Kundenprojekt ist dieser Vorgang allerdings organisatorisch anders geregelt. Dem zuständigen Team wird das Release-Bundle übergeben (z.B. per OneDrive). Anhand der Dateien im Release-Bundle können die Kollegen damit:

  • Die vorliegende Version bestimmen (VERSION) bzw. Name des ZIP-Archivs (release-bundle-v4.3.6.zip)
  • Das Risiko, das mit dem Deployment des Pakets verbunden ist, einschätzen (dtrack-metrics.env)
  • Ggf. selbst die Abhängigkeiten des Pakets verwalten und sich selbst über Schwachstellen des Pakets informieren (sbom-sharepoint-viva-connections.cdx.json)
  • Das Paket im App-Katalog importieren (hello-world.sppkg)

Zusammenfassung der CI/CD-Pipeline mit SharePoint Framework

In diesem Teil der Blogpost-Serie habe ich meine Vorstellung einer idealen Pipeline vorgestellt. Ich habe gezeigt, wie ich durchgängig Transparenz herstelle, in dem ich alle Relevanten Informationen an einem Platz sammle und bereitstelle. Außerdem habe ich gezeigt, wie man Dependency-Track nicht nur für die Verwaltung von SBOM-Informationen verwendet, sondern auch wie man dessen Analyse-Ergebnisse im weiteren Verlauf der Pipeline verwenden kann. Und ich habe das Release-Bundle vorgestellt, das alle relevanten Informationen des Releases enthält.

Zurück

© 2006-2026 exensio GmbH
Einstellungen gespeichert
Datenschutzeinstellungen

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:

 

  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
You are using an outdated browser. The website may not be displayed correctly. Close