Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/generate-attestations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Generate Artifact Attestations

on:
workflow_dispatch: # Allow manual trigger
push:
tags:
- 'v*' # Run on version tags
- 'demo-*' # Run on demo releases

permissions:
contents: read
packages: write
id-token: write # Needed for GitHub OIDC token

jobs:
generate-attestation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Generate .deb package
run: make deb-package

- name: Sign and generate attestation
uses: slsa-framework/slsa-github-generator@v1
with:
base64-subjects: ${{ steps.hash.outputs.hashes }}
provenance-trigger: 'tag'

- name: Upload attestation
uses: actions/upload-artifact@v3
with:
name: attestations
path: |
*.intoto.jsonl
*.sig

- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: |
*.intoto.jsonl
*.sig
1 change: 1 addition & 0 deletions verification/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type IHandler interface {
type Handler struct {
SessionManager sessionmanager.ISessionManager
Verifier verifier.IVerifier
InstallInfo *InstallationInfo

logger *zap.SugaredLogger
}
Expand Down
125 changes: 125 additions & 0 deletions verification/api/installation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright 2025 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package api

import (
"encoding/json"
"os"
"path/filepath"
"strings"
)

// InstallationInfo contains information about how this Veraison instance
// was installed and its artifact attestations
type InstallationInfo struct {
// Version of Veraison
Version string `json:"version"`

// Type of installation (deb, rpm, native, container)
InstallType string `json:"install_type"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I question the utility of this field. For one, these categories are not mutually-exclusive. deb and rpm deployments are by defiinition native installations (they're actually the native deployment that was packaged afterwards). And it is possible to install deb or rpm package inside a container.

It is also non-trivial to establish this (this is currently not being done correctly). The simplest fool-proof way would be to generate metadata during installation that tells you how Sevices were installed, if that is something that is actually needed.

Finally, the way this currently implemented requires awareness of possible deployment models. This is undesirable. The code shouldn't need to be aware of how it going to be deployment. For example what happens when some 3rd party packages Services for another system (e.g. as an Arch package, or some cross-distribution system such as Flatpak)? A new packaging mechanism should not require code modification.


// Installation time (when package was installed)
InstallTime string `json:"install_time,omitempty"`

// Path to the artifact attestation file if available
AttestationPath string `json:"attestation_path,omitempty"`

// Attestation digest (sha256 of the installation artifact)
ArtifactDigest string `json:"artifact_digest,omitempty"`
}

// GetInstallationInfo attempts to gather information about how this instance
// was installed and any available attestations
func GetInstallationInfo() (*InstallationInfo, error) {
info := &InstallationInfo{}

// Try to detect installation type and gather info
if isDebPackage() {
if err := getDebianInfo(info); err != nil {
return nil, err
}
} else if isRpmPackage() {
if err := getRpmInfo(info); err != nil {
return nil, err
}
} else if isContainer() {
if err := getContainerInfo(info); err != nil {
return nil, err
}
} else {
// Assume native installation
if err := getNativeInfo(info); err != nil {
return nil, err
}
}

return info, nil
}

// isDebPackage checks if this is a Debian package installation
func isDebPackage() bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only tells you that the system uses dpkg package manager. This does not tell you that Services were installed via a package.

Copy link
Contributor Author

@Sukuna0007Abhi Sukuna0007Abhi Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sir fixing it sir @setrofim

_, err := os.Stat("/var/lib/dpkg/status")
return err == nil
}

// isRpmPackage checks if this is an RPM package installation
func isRpmPackage() bool {
_, err := os.Stat("/var/lib/rpm/Packages")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto -- this only checks that the system uses rpm packages, not that Services were installed via a package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed now I think sir @setrofim

return err == nil
}

// isContainer checks if running in a container
func isContainer() bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here -- this only tells you that you're running inside a container, but not that the docker deployment was used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing it sir @setrofim

_, err := os.Stat("/.dockerenv")
if err == nil {
return true
}

data, err := os.ReadFile("/proc/1/cgroup")
if err != nil {
return false
}
return strings.Contains(string(data), "docker") ||
strings.Contains(string(data), "containerd")
}

// getDebianInfo gathers installation info from dpkg
func getDebianInfo(info *InstallationInfo) error {
info.InstallType = "deb"
// Implementation to get deb package details
// TODO: Get version from dpkg-query
// TODO: Get installation time from /var/lib/dpkg/info
// TODO: Look for attestation file in /usr/share/doc/veraison/
return nil
}

// getRpmInfo gathers installation info from RPM
func getRpmInfo(info *InstallationInfo) error {
info.InstallType = "rpm"
// Implementation to get rpm package details
// TODO: Get version from rpm -q
// TODO: Get installation time from rpm database
// TODO: Look for attestation file in /usr/share/doc/veraison/
return nil
}

// getContainerInfo gathers installation info for container deployments
func getContainerInfo(info *InstallationInfo) error {
info.InstallType = "container"
// Implementation for container deployments
// TODO: Get version from environment variable
// TODO: Get container creation time
// TODO: Look for attestation file in predefined location
return nil
}

// getNativeInfo gathers installation info for native deployments
func getNativeInfo(info *InstallationInfo) error {
info.InstallType = "native"
// Implementation for native deployments
// TODO: Get version from build info
// TODO: Get installation time from directory timestamp
// TODO: Look for attestation file in installation directory
return nil
}
48 changes: 48 additions & 0 deletions verification/api/installation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2025 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package api

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetInstallationInfo(t *testing.T) {
info, err := GetInstallationInfo()
require.NoError(t, err)
require.NotNil(t, info)

// Installation type should be one of the supported types
assert.Contains(t, []string{"deb", "rpm", "container", "native"}, info.InstallType)

// Version should not be empty
assert.NotEmpty(t, info.Version)
}

func TestIsContainer(t *testing.T) {
// Note: This test may need to be skipped depending on the environment
isContainer := isContainer()
t.Logf("Running in container: %v", isContainer)
}

func TestInstallationInfoJSON(t *testing.T) {
info := InstallationInfo{
Version: "1.0.0",
InstallType: "deb",
InstallTime: "2025-09-23T10:00:00Z",
AttestationPath: "/usr/share/doc/veraison/attestation.json",
ArtifactDigest: "sha256:1234567890abcdef",
}

data, err := json.Marshal(info)
require.NoError(t, err)

var decoded InstallationInfo
err = json.Unmarshal(data, &decoded)
require.NoError(t, err)

assert.Equal(t, info, decoded)
}