{"id":13542638,"url":"https://github.com/MagdaPaj/debian-dependency-package-generation","last_synced_at":"2025-04-02T10:31:12.355Z","repository":{"id":42374266,"uuid":"440901265","full_name":"MagdaPaj/debian-dependency-package-generation","owner":"MagdaPaj","description":null,"archived":false,"fork":false,"pushed_at":"2022-04-08T05:54:10.000Z","size":35,"stargazers_count":4,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-17T09:21:19.319Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MagdaPaj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-22T15:24:23.000Z","updated_at":"2023-10-30T05:44:16.000Z","dependencies_parsed_at":"2022-08-28T21:21:45.390Z","dependency_job_id":null,"html_url":"https://github.com/MagdaPaj/debian-dependency-package-generation","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MagdaPaj%2Fdebian-dependency-package-generation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MagdaPaj%2Fdebian-dependency-package-generation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MagdaPaj%2Fdebian-dependency-package-generation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MagdaPaj%2Fdebian-dependency-package-generation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MagdaPaj","download_url":"https://codeload.github.com/MagdaPaj/debian-dependency-package-generation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246796905,"owners_count":20835462,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T10:01:13.425Z","updated_at":"2025-04-02T10:31:12.022Z","avatar_url":"https://github.com/MagdaPaj.png","language":"Shell","funding_links":[],"categories":["others","Shell"],"sub_categories":[],"readme":"# Debian dependency package generation\n\n## Motivation\n\nIn device management, it is valuable to have the fleet of devices as consistent as possible. This helps in testing software releases and makes it easier to debug issues on remote devices.\n\nIf performing package based updates, one topic to consider is how to avoid drift between the initial device image and the state of the device fleet.\n\nOne additional consideration is that APT is very opinionated about which dependent package version to install when resolving dependencies. APT will always try to install the latest available package version that can be found in all source package repositories unless instructed differently using [APT preferences](https://manpages.debian.org/bullseye/apt/apt_preferences.5.en.html).\n\n## Approach with a dependency package\n\nA dependency package represents a desired state of a system, which is defined by a list of Debian packages with corresponding versions. All required packages are captured as dependencies in the control file of an otherwise shallow Debian package. APT will try to automatically resolve and install these dependencies when running `apt install dependency-pack`.\n\nThis repository contains pipelines and scripts for generating the Debian dependency package and its optional pinning package that modifies the APT preferences to force the installation of the exact version of the dependent package.\n\nThe dependency package can be referred to when generating the initial device image and when issuing package updates to the device fleet. This way, the same desired state should be represented in both.\n\n## Structure of dependency packages\n\nDependency packages consist of a `control` file defining the desired state by enumerating all dependencies in the `Depends` section. Packages to be removed are listed under `Conflicts`.\n\n```\nPackage: dependency-pack\nVersion: 0.0.1\nArchitecture: amd64\nMaintainer: YourName \u003cYourName@YourCompany\u003e\nDepends: dependency-a (=1.2.3-1), dependency-b(=1.9.1-3)\nConflicts: package-to-remove (=1.1.1)\nDescription: Dependency Pack.\n You can add a longer description here. Mind the space at the beginning of this paragraph.\n```\n\n## Structure of pinning packages\n\nPinning packages consist of a plain `control` file and an additional APT preference file that will be placed under `etc/apt/preferences.d/` during their installation. Every dependent package results in an entry with the following structure:\n\n```\nPackage: aziot-identity-service\nPin: version 1.2.4-1\nPin-Priority: 1001\n```\n\nThe impact of APT preferences can be inspected by running `apt-cache policy your-package-name`.\n\n## Capturing package snapshots\n\nThe `package-history` folder contains a list of package snapshots. To enable the later removal of packages that come preinstalled with the base image, the contents of the latter need to be captured as the original state. In this sample repository, the original snapshot was named `0`. Later snapshots must be named incrementally according to the timestamp of their creation (c.f. [script](./src/create-package-snapshot.sh)).\n\n## Release creation\n\nTo create a new dependency/pinning package, a new release must be created. To do so:\n\n1. create a new file under `package-history` folder using the current value of `$EPOCHSECONDS` as a file name\n2. in the newly create file, put each package name and its pinned version on a new line, e.g. `package-name (=1.1.0-1)`\n3. commit and push your changes\n4. create a new tag following the semantic versioning (e.g. `git tag v0.0.5`)\n5. push the tag `git push --tags`, this will automatically trigger a GitHub workflow that will create a new release with the dependency and pinning package as assets.\n\n## Package installation\n\nDownload the dependency package from a selected release. To install it, run:\n\n```bash\nsudo apt install ./dependency-pack.deb\n```\n\nIf there is an error with unmet dependencies because APT would like to install a newer version of a dependent package, you have multiple options to force the installation of the pinned versions.\n\n1. Install the pinning package first\n```bash\nsudo apt install ./pinning-pack.deb\nsudo apt install ./dependency-pack.deb\n```\n\n2. Inspect the dependency list manually and install every dependent package explicitly\n```bash\ndpkg-deb -f ./dependency-pack.deb control Depends\nsudo apt install ./dependency-pack.deb dependency-a=1.2.3-1 dependency-b=1.9.1-3\n```\n\n3. Use private repositories as package sources and make sure they only contain packages that match the dependent packages' versions.\n\n\n## Pipelines\n\n### Azure DevOps\nThe sample Azure DevOps [pipeline](./.azdo/pipelines/release-packages.yml) shows how to generate and publish dependency/pinning packages to Artifactory. It assumes that multiple distinct environments are targeted: DEV, TEST, PROD. For each of these environments, a distinct variable group needs to be preconfigured in Azure DevOps. Each of these groups is expected to contain the following variables:\n- ARTIFACTORY-USERNAME: The username authorized to push packages to Artifactory\n- ARTIFACTORY-PASSWORD: The password authenticating the ARTIFACTORY-USERNAME\n- ARTIFACTORY-URL: The base URL of the targeted Artifactory instance, e.g. https://{your-instance}.jfrog.io/artifactory/{your-repository}\n\nThe TEST and PROD stages require the manual approval of an authorized Azure DevOps user before they are executed.\n\nIn order to allow the pipeline to push the tag to the GIT repository, make sure to allow the \"Build Service\" to contribute to the corresponding repository (AzDo-\u003eProject Settings-\u003eRepositories-\u003e{Your Repo}-\u003eSecurity-\u003e{* Build Service}-\u003eContribute-\u003eAllow).\n\n### GitHub\nThe sample GitHub [workflow](./.github/workflows/generate-package.yml) shows how to generate and publish dependency/pinning packages using the built-in GitHub Releases.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMagdaPaj%2Fdebian-dependency-package-generation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMagdaPaj%2Fdebian-dependency-package-generation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMagdaPaj%2Fdebian-dependency-package-generation/lists"}