# Dockerfile Pin/Unpin Design
## Use Cases
- [UC1] Pins/unpins a dockerfile when presented with the path
- [UC2] Prints the latest tag and rpms available for a dockerfile's ubi
- Goal: have a rpm manifest of the latest available packages to transparently inform the user of what exactly will happen when we pin or unpin a generic `ubi-minimal` container
## Design
### Steps
- [UC1]
- Called from `oadp_update_release.py` with `--codefreeze [True/False]`
- Must provide True/False
- False = unpinned
- True = pinned
- Update the `follow_tag` and `microdnf` sections of the dockerfile
- Unpinned
```
#@follow_tag(registry.redhat.io/ubi8/ubi-minimal:latest)
FROM registry.redhat.io/ubi8/ubi-minimal:8.6-751
RUN microdnf -y update && microdnf -y clean all
```
- Pinned
```
#@FOLLOW_TAG(registry.redhat.io/ubi8/ubi-minimal:latest)
FROM registry.redhat.io/ubi8/ubi-minimal:8.6-751
#RUN microdnf -y update && microdnf -y clean all
```
- [UC2]
- Determine the rpm set of all package nvrs available to the image and add line to dockerfiles
- Spin up a container to update
- diff of `ubi8` before and after updates
```
--- /tmp/rpms_before.txt
+++ /tmp/rpms_after.txt
@@ -15,9 +15,11 @@
filesystem-3.8-6.el8.x86_64
gawk-4.2.1-4.el8.x86_64
glib2-2.56.4-158.el8.x86_64
-glibc-2.28-189.1.el8.x86_64
-glibc-common-2.28-189.1.el8.x86_64
-glibc-minimal-langpack-2.28-189.1.el8.x86_64
+glibc-2.28-189.5.el8_6.x86_64
+glibc-common-2.28-189.5.el8_6.x86_64
+glibc-gconv-extra-2.28-189.5.el8_6.x86_64
+glibc-langpack-en-2.28-189.5.el8_6.x86_64
+glibc-minimal-langpack-2.28-189.5.el8_6.x86_64
gmp-6.1.2-10.el8.x86_64
gnupg2-2.2.20-2.el8.x86_64
gnutls-3.6.16-4.el8.x86_64
```
- Unpinned
```
#@follow_tag(registry.redhat.io/ubi8/ubi-minimal:latest)
FROM registry.redhat.io/ubi8/ubi-minimal:8.6-751
RUN microdnf -y update && microdnf -y clean all
```
- Pinned
```
#@FOLLOW_TAG(registry.redhat.io/ubi8/ubi-minimal:latest)
FROM registry.redhat.io/ubi8/ubi-minimal:8.6-751
RUN microdnf -y install glibc-2.28-189.5.el8_6 glibc-common-2.28-189.5.el8_6 glibc-gconv-extra-2.28-189.5.el8_6 glibc-langpack-en-2.28-189.5.el8_6 glibc-minimal-langpack-2.28-189.5.el8_6 && microdnf clean all
#RUN microdnf -y update && microdnf -y clean all
```
- Use the [`podman-py`](https://github.com/containers/podman-py) library
- [Example: Chapter 18. Using the container-tools API](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/building_running_and_managing_containers/assembly_using-the-container-tools-api_building-running-and-managing-containers)
- ```
yum install podman-remote
systemctl --user enable --now podman.socket
systemctl --user status podman.socket
ls /run/user/1000/podman/podman.sock
```
### Design Decisions?
- <Rayford> introduce “intermediate” image for OADP to facilitate/centralize pinning/unpinning instead of using `ubi-minimal` directly
- Current: `ubi-minimal` -> `oadp-IMAGE`
- Proposed: `ubi-minimal` -> `oadp-based-ubi-minimal` -> `oadp-IMAGE`
- Uses current & in-development code; narrows the scope where the changes are required
- may be more of an implementation detail than design...
- **not an item for Selena to implement**
### Questions
- N/A
### Notes
- Place in https://gitlab.cee.redhat.com/mig-integration/migint-release-tools/-/tree/main/release_tools
- DockerFiles in https://code.engineering.redhat.com/gerrit/plugins/gitiles/oadp/+/refs/heads/OADP-1.1-rhel-8/distgit/containers
- `ubi8` image located at https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8?tag=all
- `follow_tag` decorator script in https://gitlab.cee.redhat.com/cpaas-midstream/product-ci-cd/-/blob/main/stdci_libs/dockerfile_utilities.py
## Next Steps
- Integrate `dockerfile_pin.py` into `oadp_update_release.py`
- Add pinned + errata workflow to https://gitlab.cee.redhat.com/mig-integration/migint-release-tools/-/blob/main/container_pin_unpin.py
### errata update
- New Feature 7/13 (2022-JUL-13)
```
container_pin_unpin.py --grades https://errata.devel.redhat.com/errata/container/92118
```
* something LIKE the above, get grades
* list out grades via cli
* getting the grades and rpm info will need Rayford's input
```
container_pin_unpin.py --codefreeze --grades-update
```
* <Rayford> Not so much concerned with "this container is grade: [ABCDEF]" as with "this container should update to at least `package-NVR`"
* If grade is `c` or below, get the rpm(s) required for update
* <Rayford>: should be concerned for anything less than an A
* <Rayford>: it is also possible for an "A" to still have CVEs against it
* Use the ubi8 local image to see if the update can be installed/updated
* Add a line to the PINNED version of the dockerfile to yum update to fixed NVR of the rpm
```
microdnf update rsync-1.2.3
```
### Discussion Items:
* When pinned and updating for CVEs, is it acceptable to bring in any non-CVE-related updates? **NO**
* ~~If yes, then result is same as unpin and pin~~
* If no, should CVE-specific package updates be on their own line or may they co-exist on the pinned `update <package-nvr> ... && clean all` line? **co-exist**
* If co-exist,
* unpin logic remains unchanged
* pin logic must accommodate
* ~~If separate line, unpin should account for and remove *package-updates-for-CVEs* line:~~
`RUN ... <fixed-package-nvr> && ... all # OADP-RHSA-updates`
#### Decisions:
* must be able to update **only** CVE packages
* append CVE package-nvr to pinned update RPMs line
* have a `--cve-report` argument which shows image grade & any CVE packages
```
oadp-operator-1.1.0-NN (A)
...
oadp-registry-1.1.0-NN (B):
Packages: [
"httpd-2.4.37-43.module+el8.5.0+14530+6f259f31.3.x86_64",
"httpd-filesystem-2.4.37-43.module+el8.5.0+14530+6f259f31.3.noarch",
"httpd-tools-2.4.37-43.module+el8.5.0+14530+6f259f31.3.x86_64",
"mod_http2-1.15.7-3.module+el8.4.0+8625+d397f3da.x86_64",
"libssh-0.9.4-3.el8.x86_64",
"libssh-config-0.9.4-3.el8.noarch"
]
oadp-velero-plugin-for-... (A)
```
* have a `--update-cve-packages` argument which will append the cve-package-nvr to the existing pinned `update package-nvr cve-package-nvr && microdnf clean all` line
##### Sample of OADP 1.1 images (by full NVR):
1.1
```
oadp-kubevirt-velero-plugin-container-1.1.0-12
oadp-mustgather-container-1.1.0-30
oadp-operator-bundle-container-1.1.0-36
oadp-operator-container-1.1.0-24
oadp-velero-container-1.1.0-16
oadp-velero-plugin-container-1.1.0-12
oadp-velero-plugin-for-aws-container-1.1.0-11
oadp-velero-plugin-for-csi-container-1.1.0-14
oadp-velero-plugin-for-gcp-container-1.1.0-11
oadp-velero-plugin-for-microsoft-azure-container-1.1.0-11
oadp-velero-restic-restore-helper-container-1.1.0-14
oadp-volume-snapshot-mover-container-1.1.0-12
```
1.0
```
oadp-kubevirt-velero-plugin-container-1.0.3-2
oadp-velero-container-1.0.3-2
oadp-velero-plugin-container-1.0.3-2
oadp-velero-plugin-for-aws-container-1.0.3-2
oadp-velero-plugin-for-gcp-container-1.0.3-2
oadp-velero-plugin-for-microsoft-azure-container-1.0.3-2
oadp-velero-restic-restore-helper-container-1.0.3-2
oadp-registry-container-1.0.3-3
oadp-velero-plugin-for-csi-container-1.0.3-4
oadp-operator-container-1.0.3-15
oadp-mustgather-container-1.0.3-21
oadp-operator-bundle-container-1.0.3-19
```
---
# Rayford's scratch area
This should demonstrate a relatively programmatic way to identify affected package(s) for a given image.
>For Selena:
```
alias curl-pyxis="curl -X 'GET' -s --key ~/certs/sechen-brew.key --cert ~/certs/sechen-brew.crt -H 'Accept: application/json' -H 'Content-Type: application/json' "
```
#### Image with no CVEs against it (oadp-registry-container-1.1.0-8): **A**
Collect the image's vulnerabilities API url(s):
```
curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/nvr/oadp-registry-container-1.1.0-8' \
| jq -r '.data[] | .architecture, ._links.vulnerabilities'
s390x
{
"href": "/v1/images/id/62bc8854f5a0de37689c94b1/vulnerabilities"
}
amd64
{
"href": "/v1/images/id/62bc8855f5a0de37689c94b5/vulnerabilities"
}
ppc64le
{
"href": "/v1/images/id/62bc8857f5a0de37689c94b9/vulnerabilities"
}
```
*NOTE*: we will have one entry for each arch.
Hit the image's vulnerabilities API url (amd64):
```
curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/id/62bc8855f5a0de37689c94b5/vulnerabilities' \
| jq '.data[] | { "CVE": .cve_id, "Packages": [.packages[].rpm_nvra[]] }'
```
*NOTE*: no results returned for filter
#### Image with CVEs against it (oadp-registry-container-1.0.2-9): **C**
Collect the image's vulnerabilities API url(s):
```
curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/nvr/oadp-registry-container-1.0.2-9' \
| jq -r '.data[] | .architecture, ._links.vulnerabilities'
amd64
{
"href": "/v1/images/id/624b33ed702c5667e7ee585b/vulnerabilities"
}
```
Hit the image's vulnerabilities API url:
```
curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/id/624b33ed702c5667e7ee585b/vulnerabilities' \
| jq '.data[] | { "CVE": .cve_id, "Packages": [.packages[].rpm_nvra[]] }'
{
"CVE": "CVE-2022-1271",
"Packages": [
"gzip-1.9-12.el8.x86_64"
]
}
{
"CVE": "CVE-2018-25032",
"Packages": [
"zlib-1.2.11-17.el8.x86_64"
]
}
{
"CVE": "CVE-2021-33193",
"Packages": [
...<snip>...
"CVE": "CVE-2021-44224",
"Packages": [
"httpd-2.4.37-43.module+el8.5.0+14530+6f259f31.3.x86_64",
"httpd-filesystem-2.4.37-43.module+el8.5.0+14530+6f259f31.3.noarch",
"httpd-tools-2.4.37-43.module+el8.5.0+14530+6f259f31.3.x86_64",
"mod_http2-1.15.7-3.module+el8.4.0+8625+d397f3da.x86_64"
]
}
{
"CVE": "CVE-2021-3634",
"Packages": [
"libssh-0.9.4-3.el8.x86_64",
"libssh-config-0.9.4-3.el8.noarch"
]
}
```
This reflects those reported on the advisory for the image.

Cheers!
---
For posterity, look at `freshness_grades` for CHI score. We'll need to consider end_date, if present, and determine "current" score because there will be one or more grades.
Unhealthy:
```
$ curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/nvr/oadp-registry-container-1.0.2-9' \
| jq -r '.data[].freshness_grades[] '
{
"creation_date": "2022-05-27T07:13:35.267000+00:00",
"end_date": "2022-07-25T00:00:00+00:00",
"grade": "C",
"start_date": "2022-05-27T07:13:00+00:00"
}
{
"creation_date": "2022-05-27T07:13:35.267000+00:00",
"end_date": "2023-04-26T00:00:00+00:00",
"grade": "D",
"start_date": "2022-07-25T00:00:00+00:00"
}
{
"creation_date": "2022-05-27T07:13:35.267000+00:00",
"grade": "F",
"start_date": "2023-04-26T00:00:00+00:00"
}
```
Healthy:
```
$ curl -X 'GET' -s --user ':' --negotiate \
-H "Accept: application/json" -H 'Content-Type: application/json' \
'https://pyxis.engineering.redhat.com/v1/images/nvr/oadp-registry-container-1.1.0-8' \
| jq -r '.data[].freshness_grades[] '
{
"creation_date": "2022-06-29T17:14:02.799000+00:00",
"grade": "A",
"start_date": "2022-06-29T17:14:00+00:00"
}
{
"creation_date": "2022-06-29T17:14:06.082000+00:00",
"grade": "A",
"start_date": "2022-06-29T17:14:00+00:00"
}
{
"creation_date": "2022-06-29T17:14:07.769000+00:00",
"grade": "A",
"start_date": "2022-06-29T17:14:00+00:00"
}
```
---
for RHSA:
```
curl-pyxis 'https://pyxis.engineering.redhat.com/v1/images/id/624b33ed702c5667e7ee585b/vulnerabilities' | jq '.data[] | { "RHSA": .advisory_id, "CVE": .cve_id, "Packages": [.packages[].rpm_nvra[]] }'
```
---
for containers:
```
brew latest-build --quiet --all OADP-1.1-rhel-8-container-candidate | awk '{print $1}' | grep -v 'oadp-registry'
```