diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c7584e559..ef4f80a7d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -110,6 +110,8 @@ jobs: export YARN_VERSION=$(yarn --version) export WEBPACK_VERSION=$(yarn list webpack --depth=0 | grep webpack | awk -F@ '{print $2}') export BUILDNUMBER=${GITHUB_RUN_NUMBER} + GIT_COMMIT_HASH_LONG=${{ github.sha }} + export GIT_COMMIT_HASH_SHORT={GIT_COMMIT_HASH_LONG:0:7} make build-all PLATFORM=${{ matrix.config.platform }} ARCH=${{ matrix.config.arch }} ENV=${NODE_ENV} env: CONTAINER_IMAGE_TAG: ${{ env.CONTAINER_IMAGE_TAG }} diff --git a/api/build/variables.go b/api/build/variables.go index d20f64c42..2d5ab4ec0 100644 --- a/api/build/variables.go +++ b/api/build/variables.go @@ -1,9 +1,12 @@ package build +import "runtime" + // Variables to be set during the build time var BuildNumber string var ImageTag string var NodejsVersion string var YarnVersion string var WebpackVersion string -var GoVersion string +var GoVersion string = runtime.Version() +var GitCommit string diff --git a/api/http/handler/system/handler.go b/api/http/handler/system/handler.go index 515fe4390..dadcd2ec7 100644 --- a/api/http/handler/system/handler.go +++ b/api/http/handler/system/handler.go @@ -47,7 +47,7 @@ func NewHandler(bouncer security.BouncerService, authenticatedRouter := router.PathPrefix("/").Subrouter() authenticatedRouter.Use(bouncer.AuthenticatedAccess) - authenticatedRouter.Handle("/version", http.HandlerFunc(h.version)).Methods(http.MethodGet) + authenticatedRouter.Handle("/version", httperror.LoggerHandler(h.version)).Methods(http.MethodGet) authenticatedRouter.Handle("/nodes", httperror.LoggerHandler(h.systemNodesCount)).Methods(http.MethodGet) authenticatedRouter.Handle("/info", httperror.LoggerHandler(h.systemInfo)).Methods(http.MethodGet) diff --git a/api/http/handler/system/version.go b/api/http/handler/system/version.go index 8972627f7..7af0b2aea 100644 --- a/api/http/handler/system/version.go +++ b/api/http/handler/system/version.go @@ -2,10 +2,13 @@ package system import ( "net/http" + "os" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/build" "github.com/portainer/portainer/api/http/client" + "github.com/portainer/portainer/api/http/security" + httperror "github.com/portainer/portainer/pkg/libhttp/error" "github.com/portainer/portainer/pkg/libhttp/response" "github.com/coreos/go-semver/semver" @@ -32,6 +35,8 @@ type BuildInfo struct { YarnVersion string WebpackVersion string GoVersion string + GitCommit string + Env []string `json:",omitempty"` } // @id systemVersion @@ -44,7 +49,11 @@ type BuildInfo struct { // @produce json // @success 200 {object} versionResponse "Success" // @router /system/version [get] -func (handler *Handler) version(w http.ResponseWriter, r *http.Request) { +func (handler *Handler) version(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { + isAdmin, err := security.IsAdmin(r) + if err != nil { + return httperror.Forbidden("Permission denied to access Portainer", err) + } result := &versionResponse{ ServerVersion: portainer.APIVersion, @@ -57,16 +66,21 @@ func (handler *Handler) version(w http.ResponseWriter, r *http.Request) { YarnVersion: build.YarnVersion, WebpackVersion: build.WebpackVersion, GoVersion: build.GoVersion, + GitCommit: build.GitCommit, }, } + if isAdmin { + result.Build.Env = os.Environ() + } + latestVersion := GetLatestVersion() if HasNewerVersion(portainer.APIVersion, latestVersion) { result.UpdateAvailable = true result.LatestVersion = latestVersion } - response.JSON(w, &result) + return response.JSON(w, &result) } func GetLatestVersion() string { diff --git a/app/react/portainer/system/useSystemVersion.ts b/app/react/portainer/system/useSystemVersion.ts index ce502d8ed..9b288864b 100644 --- a/app/react/portainer/system/useSystemVersion.ts +++ b/app/react/portainer/system/useSystemVersion.ts @@ -21,6 +21,8 @@ export interface VersionResponse { YarnVersion: string; WebpackVersion: string; GoVersion: string; + GitCommit: string; + Env?: string[]; }; } diff --git a/app/react/sidebar/Footer/BuildInfoModal.tsx b/app/react/sidebar/Footer/BuildInfoModal.tsx index 25041fcfd..fc81e3a3c 100644 --- a/app/react/sidebar/Footer/BuildInfoModal.tsx +++ b/app/react/sidebar/Footer/BuildInfoModal.tsx @@ -1,8 +1,18 @@ import { useState } from 'react'; -import { Database, Hash, Server, Tag, Wrench } from 'lucide-react'; +import { + Database, + GitCommit, + Hash, + Server, + Tag, + Variable, + Wrench, +} from 'lucide-react'; +import clsx from 'clsx'; import { useSystemStatus } from '@/react/portainer/system/useSystemStatus'; import { useSystemVersion } from '@/react/portainer/system/useSystemVersion'; +import { useCurrentUser } from '@/react/hooks/useUser'; import { Modal } from '@@/modals'; import { Button } from '@@/buttons'; @@ -37,6 +47,7 @@ export function BuildInfoModalButton() { } function BuildInfoModal({ closeModal }: { closeModal: () => void }) { + const { isAdmin } = useCurrentUser(); const versionQuery = useSystemVersion(); const statusQuery = useSystemStatus(); @@ -82,6 +93,13 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) { + + + + Git Commit: {Build.GitCommit} + + + @@ -102,6 +120,25 @@ function BuildInfoModal({ closeModal }: { closeModal: () => void }) { Go v{Build.GoVersion} + + {isAdmin && Build.Env && ( +
+ + + Environment Variables + + +
+ {Build.Env.map((envVar) => ( +
+ {envVar} +
+ ))} +
+
+ )}