init
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use nix
|
62
.gitignore
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# History files
|
||||||
|
.Rhistory
|
||||||
|
.Rapp.history
|
||||||
|
|
||||||
|
# Session Data files
|
||||||
|
.RData
|
||||||
|
.RDataTmp
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
.Ruserdata
|
||||||
|
|
||||||
|
# Example code in package build process
|
||||||
|
*-Ex.R
|
||||||
|
|
||||||
|
# Output files from R CMD build
|
||||||
|
/*.tar.gz
|
||||||
|
|
||||||
|
# Output files from R CMD check
|
||||||
|
/*.Rcheck/
|
||||||
|
|
||||||
|
# RStudio files
|
||||||
|
.Rproj.user/
|
||||||
|
|
||||||
|
# produced vignettes
|
||||||
|
vignettes/*.html
|
||||||
|
vignettes/*.pdf
|
||||||
|
|
||||||
|
# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
|
||||||
|
.httr-oauth
|
||||||
|
|
||||||
|
# knitr and R markdown default cache directories
|
||||||
|
*_cache/
|
||||||
|
/cache/
|
||||||
|
|
||||||
|
# Temporary files created by R markdown
|
||||||
|
*.utf8.md
|
||||||
|
*.knit.md
|
||||||
|
|
||||||
|
# R Environment Variables
|
||||||
|
.Renviron
|
||||||
|
|
||||||
|
# pkgdown site
|
||||||
|
docs/
|
||||||
|
|
||||||
|
# translation temp files
|
||||||
|
po/*~
|
||||||
|
|
||||||
|
# RStudio Connect folder
|
||||||
|
rsconnect/
|
||||||
|
|
||||||
|
.direnv
|
||||||
|
*_files
|
||||||
|
*.html
|
||||||
|
*.tex
|
||||||
|
*.typ
|
||||||
|
*.pdf
|
||||||
|
/*.zip
|
||||||
|
|
||||||
|
_book
|
||||||
|
/.quarto/
|
||||||
|
|
||||||
|
result*
|
8
_extensions/shafayetShafee/bsicons/_extension.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
title: Support for Bootstrap Icons
|
||||||
|
author: Shafayet Khan Shafee
|
||||||
|
version: 1.0.0
|
||||||
|
quarto-required: ">=1.2.0"
|
||||||
|
contributes:
|
||||||
|
shortcodes:
|
||||||
|
- bsicons.lua
|
||||||
|
|
2079
_extensions/shafayetShafee/bsicons/assets/css/all.css
Normal file
66
_extensions/shafayetShafee/bsicons/bsicons.lua
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
local function ensureHtmlDeps()
|
||||||
|
quarto.doc.addHtmlDependency({
|
||||||
|
name = "bootstrap-icons",
|
||||||
|
version = "1.11.1",
|
||||||
|
stylesheets = {"assets/css/all.css"}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function isEmpty(s)
|
||||||
|
return s == nil or s == ''
|
||||||
|
end
|
||||||
|
|
||||||
|
local str = pandoc.utils.stringify
|
||||||
|
|
||||||
|
return {
|
||||||
|
["bi"] = function(args, kwargs)
|
||||||
|
local icon = str(args[1])
|
||||||
|
local size = str(kwargs["size"])
|
||||||
|
local color = str(kwargs["color"])
|
||||||
|
local label = str(kwargs["label"])
|
||||||
|
local class = str(kwargs["class"])
|
||||||
|
|
||||||
|
if not isEmpty(size) then
|
||||||
|
size = "font-size: " .. size .. ";"
|
||||||
|
else
|
||||||
|
size = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
if not isEmpty(color) then
|
||||||
|
color = "color: " .. color .. ";"
|
||||||
|
else
|
||||||
|
color = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
local style = "style=\"" .. size .. color .. "\""
|
||||||
|
|
||||||
|
if not isEmpty(label) then
|
||||||
|
label = " aria-label=\"" .. label .. "\""
|
||||||
|
end
|
||||||
|
|
||||||
|
if isEmpty(class) then
|
||||||
|
class = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
local role = "role=\"img\""
|
||||||
|
local aria_hidden = "aria-hidden=\"true\""
|
||||||
|
|
||||||
|
if quarto.doc.isFormat("html:js") then
|
||||||
|
ensureHtmlDeps()
|
||||||
|
if isEmpty(label) then
|
||||||
|
return pandoc.RawInline(
|
||||||
|
'html',
|
||||||
|
"<i class=\"bi-" .. icon .. " " .. class .. "\"" .. style .. role .. aria_hidden .. "></i>"
|
||||||
|
)
|
||||||
|
else
|
||||||
|
return pandoc.RawInline(
|
||||||
|
'html',
|
||||||
|
"<i class=\"bi-" .. icon .. " " .. class .. "\"" .. style .. role .. label .. "></i>"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return pandoc.Null()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
}
|
14
_extensions/shafayetShafee/metropolis-beamer/_extension.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
title: Metropolis-beamer
|
||||||
|
author: shafayetShafee
|
||||||
|
version: 1.0.0
|
||||||
|
quarto-required: ">=1.4.0"
|
||||||
|
contributes:
|
||||||
|
formats:
|
||||||
|
revealjs:
|
||||||
|
date-format: long
|
||||||
|
theme: [simple, custom.scss]
|
||||||
|
filters:
|
||||||
|
- metropolis-header.lua
|
||||||
|
- custom-block.lua
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Shafayet Khan Shafee
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local str = pandoc.utils.stringify
|
||||||
|
|
||||||
|
if quarto.doc.is_format('revealjs') then
|
||||||
|
function Callout(el)
|
||||||
|
if el.type == 'none' then
|
||||||
|
el.type = 'note'
|
||||||
|
el.icon = false
|
||||||
|
el.appearance = 'default'
|
||||||
|
return el
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
325
_extensions/shafayetShafee/metropolis-beamer/custom.scss
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&family=Yanone+Kaffeesatz:wght@200..700&display=swap');
|
||||||
|
|
||||||
|
@import "icon.scss";
|
||||||
|
|
||||||
|
/*-- scss:defaults --*/
|
||||||
|
|
||||||
|
$font-family-sans-serif: "Fira Sans", Helvetica, sans-serif !default;
|
||||||
|
$font-family-monospace: "Source Code Pro", monospace !default;
|
||||||
|
$presentation-h-font12: "Yanone Kaffeesatz", sans-serif !default;
|
||||||
|
$presentation-h-font36: "Source Sans 3", sans-serif !default;
|
||||||
|
$presentation-font-size-root: 32px !default;
|
||||||
|
$presentation-h1-font-size: 2.5em !default;
|
||||||
|
$presentation-h2-font-size: 2em !default;
|
||||||
|
$presentation-h3-font-size: 1.4em !default;
|
||||||
|
$presentation-font-smaller: 0.7 !default;
|
||||||
|
$presentation-line-height: 1.3 !default;
|
||||||
|
$presentation-title-slide-text-align: left !default;
|
||||||
|
$presentation-slide-text-align: left !default;
|
||||||
|
$code-block-font-size: 0.60em !default;
|
||||||
|
|
||||||
|
$primary-color: #23373b !default;
|
||||||
|
$secondary-color: #EB811B !default;
|
||||||
|
$body-fg-color: #33474b !default;
|
||||||
|
$alert-color: #9c162a !default;
|
||||||
|
$example-color: #14B03D !default;
|
||||||
|
$body-bg: #f1f1f1 !default;
|
||||||
|
$body-color: $body-fg-color !default;
|
||||||
|
|
||||||
|
$header-bg-color: $primary-color !default;
|
||||||
|
$selection-bg-color: #26351C !default;
|
||||||
|
$selection-fcolor: #fff !default;
|
||||||
|
$dark-bg-code-color: $example-color !default;
|
||||||
|
$link-color: $secondary-color !default;
|
||||||
|
|
||||||
|
$titleSlide-line: solid !default;
|
||||||
|
$h12-font-weight: 500 !default;
|
||||||
|
$h36-font-weight: 400 !default;
|
||||||
|
$cell-code-font-weight: normal !default;
|
||||||
|
$body-font-weight: 300 !default;
|
||||||
|
$authors-block-gap: 4em !default;
|
||||||
|
|
||||||
|
/*-- scss:rules --*/
|
||||||
|
|
||||||
|
.reveal {
|
||||||
|
font-weight: $body-font-weight !important;
|
||||||
|
|
||||||
|
h1, h2 {
|
||||||
|
font-family: $presentation-h-font12;
|
||||||
|
font-weight: $h12-font-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3, h4, h5, h6 {
|
||||||
|
font-family: $presentation-h-font36;
|
||||||
|
font-weight: $h36-font-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-weight: $cell-code-font-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: $h12-font-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin-left: 1em;
|
||||||
|
|
||||||
|
p {
|
||||||
|
padding: 5px;
|
||||||
|
line-height: 1.2;
|
||||||
|
color: lighten(#604c38, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sourceCode {
|
||||||
|
margin-top: 15px;
|
||||||
|
box-shadow: 0px 0px 6px rgba(0,0,0,.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.sourceCode code {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert { color: $alert-color; }
|
||||||
|
.example { color: $example-color; }
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
color: $selection-fcolor;
|
||||||
|
background: $selection-bg-color;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout {
|
||||||
|
box-shadow: 0px 0px 6px rgba(0,0,0,.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.callout-body {
|
||||||
|
font-weight: $body-font-weight !important;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section#references {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.csl-entry {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
font-weight: $cell-code-font-weight;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.csl-entry::before {
|
||||||
|
content: $book-icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
.institute,
|
||||||
|
.quarto-title-affiliation,
|
||||||
|
.quarto-title-author-email {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quarto-title-authors {
|
||||||
|
padding-top: 20px;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 3.5rem;
|
||||||
|
border-top: 2px $titleSlide-line $secondary-color;
|
||||||
|
|
||||||
|
.quarto-title-author {
|
||||||
|
padding-left: 0em !important;
|
||||||
|
padding-right: $authors-block-gap !important;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.author,
|
||||||
|
.quarto-title-author-name {
|
||||||
|
color: $body-color;
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title-slide .subtitle,
|
||||||
|
div.reveal div.slides section.quarto-title-block .subtitle {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-background.title-slide {
|
||||||
|
background-color: $primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.header-logo {
|
||||||
|
grid-area: logo;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.header-title {
|
||||||
|
grid-area: ht;
|
||||||
|
padding-left: 60px;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.reveal-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 0.35fr;
|
||||||
|
grid-template-areas: "ht logo";
|
||||||
|
column-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
top: -5px;
|
||||||
|
margin: 3.2px 0px 2px 0px;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
background: $header-bg-color;
|
||||||
|
z-index: 5;
|
||||||
|
|
||||||
|
.hedaer-title h2 {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.slides section:not(.title-slide):not(#title-slide):not(.stack) {
|
||||||
|
padding-top: 1.5em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
padding-bottom: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.slides section.smaller:not(.title-slide):not(#title-slide):not(.stack) {
|
||||||
|
padding-top: 4em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-logo img,
|
||||||
|
.header-logo svg{
|
||||||
|
margin: 0px 0px 0px 0px;
|
||||||
|
padding-left: 3vw;
|
||||||
|
padding-right: 18px;
|
||||||
|
padding-top: 12px;
|
||||||
|
height: 100%;
|
||||||
|
width: auto;
|
||||||
|
max-width: max(80px, 12vw);
|
||||||
|
max-height: max(80px, 12vh);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-output-display {
|
||||||
|
max-height: 450px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer,
|
||||||
|
.slide-number {
|
||||||
|
color: #604c38;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide aside {
|
||||||
|
bottom: 250px ;
|
||||||
|
color: #604c38;
|
||||||
|
}
|
||||||
|
|
||||||
|
section[data-background-image] {
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h5 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: $example-color;
|
||||||
|
filter: brightness(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
background-color: transparent;
|
||||||
|
color: $secondary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tables
|
||||||
|
.slides table {
|
||||||
|
|
||||||
|
margin-bottom: 0.80em;
|
||||||
|
border-top: 2px solid lighten(#505453, 5%);
|
||||||
|
border-bottom: 2px solid lighten(#505453, 5%);
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
border: none;
|
||||||
|
padding: 0.20em;
|
||||||
|
font-size: 0.90em;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead th,
|
||||||
|
tr:last-child td {
|
||||||
|
border-bottom: 1px solid lighten(#505453, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide {
|
||||||
|
figure>figcaption {
|
||||||
|
font-size: 0.80em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
figure.quarto-float-tbl figcaption.quarto-float-caption-top {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div[type="default"],
|
||||||
|
div[type="example"],
|
||||||
|
div[type="alert"] {
|
||||||
|
|
||||||
|
.callout {
|
||||||
|
border-radius: 0px;
|
||||||
|
box-shadow: 0px 0px 6px rgba(0, 0, 0, .05);
|
||||||
|
}
|
||||||
|
.callout.callout-style-default {
|
||||||
|
border-left: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.callout-note {
|
||||||
|
border-left-color: silver !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.callout-note.callout-style-default .callout-title {
|
||||||
|
background-color: #bebebe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div[type="example"] {
|
||||||
|
div.callout-note.callout-style-default .callout-title {
|
||||||
|
color: $example-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div[type="alert"] {
|
||||||
|
div.callout-note.callout-style-default .callout-title {
|
||||||
|
color: $alert-color;
|
||||||
|
}
|
||||||
|
}
|
3
_extensions/shafayetShafee/metropolis-beamer/icon.scss
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Shafayet Khan Shafee
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local str = pandoc.utils.stringify
|
||||||
|
|
||||||
|
local function ensureHtmlDeps()
|
||||||
|
quarto.doc.add_html_dependency({
|
||||||
|
name = "metropolis-beamer",
|
||||||
|
version = "1.0.0",
|
||||||
|
scripts = {
|
||||||
|
{
|
||||||
|
path = "resources/js/add_header.js",
|
||||||
|
attribs = {defer = "true"},
|
||||||
|
afterBody = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if quarto.doc.is_format('revealjs') then
|
||||||
|
-- Ensuring the dependencies got loaded before proceeding
|
||||||
|
ensureHtmlDeps()
|
||||||
|
|
||||||
|
function Span(el)
|
||||||
|
local style = el.attributes["style"] or ""
|
||||||
|
local color = el.attributes['color']
|
||||||
|
local bg_color = el.attributes['bg']
|
||||||
|
|
||||||
|
if color then
|
||||||
|
local fcolor = "color: " .. color .. ";"
|
||||||
|
el.attributes['color'] = nil
|
||||||
|
style = style .. ";" .. fcolor
|
||||||
|
end
|
||||||
|
if bg_color then
|
||||||
|
local bcolor = "background-color: " .. bg_color .. ";"
|
||||||
|
el.attributes['bg-color'] = nil
|
||||||
|
style = style .. ";" .. bcolor
|
||||||
|
end
|
||||||
|
|
||||||
|
el.attributes['style'] = style
|
||||||
|
return el
|
||||||
|
end
|
||||||
|
|
||||||
|
function Pandoc(doc)
|
||||||
|
local blocks = doc.blocks
|
||||||
|
local str = pandoc.utils.stringify
|
||||||
|
local meta = doc.meta
|
||||||
|
-- make divs structure for holding text and logo.
|
||||||
|
local header_logo = meta['header-logo'] and str(meta['header-logo']) or ""
|
||||||
|
local header_logo_link = meta['header-logo-link'] and str(meta['header-logo-link']) or ""
|
||||||
|
local header_img = pandoc.Div(pandoc.Image("", header_logo, ""), {class = "header-logo"})
|
||||||
|
|
||||||
|
if header_logo_link ~= "" then
|
||||||
|
header_img.attributes['header-logo-link'] = header_logo_link
|
||||||
|
end
|
||||||
|
|
||||||
|
local header_title = pandoc.Div({pandoc.Para(' ')} ,{class = "header-title"})
|
||||||
|
|
||||||
|
local div = pandoc.Div(
|
||||||
|
{
|
||||||
|
header_title,
|
||||||
|
header_img
|
||||||
|
},
|
||||||
|
{class = 'reveal-header'})
|
||||||
|
table.insert(blocks, div)
|
||||||
|
return doc
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,109 @@
|
||||||
|
/**
|
||||||
|
* reveal-header
|
||||||
|
* A filter that adds header text and logo.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2023-2024 Shafayet Khan Shafee.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function header() {
|
||||||
|
|
||||||
|
// add the header structure as the firstChild of div.reveal-header
|
||||||
|
function add_header() {
|
||||||
|
let header = document.querySelector("div.reveal-header");
|
||||||
|
let reveal = document.querySelector(".reveal");
|
||||||
|
reveal.insertBefore(header, reveal.firstChild);
|
||||||
|
|
||||||
|
let header_title_p_placeholder = document.querySelector('div.header-title > p');
|
||||||
|
let header_title_h2_placeholder = document.createElement('h2');
|
||||||
|
header_title_p_placeholder.replaceWith(header_title_h2_placeholder);
|
||||||
|
|
||||||
|
logo_img = document.querySelector('.header-logo > img');
|
||||||
|
if (logo_img?.getAttribute('src') == null) {
|
||||||
|
if (logo_img?.getAttribute('data-src') != null) {
|
||||||
|
logo_img.src = logo_img?.getAttribute('data-src') || "";
|
||||||
|
logo_img.removeAttribute('data-src');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function make_h2_title() {
|
||||||
|
let h2_text = Reveal.getCurrentSlide().getAttribute('data-h2-text');
|
||||||
|
let header_title_placeholder = document.querySelector('div.header-title > h2');
|
||||||
|
header_title_placeholder.innerText = h2_text;
|
||||||
|
|
||||||
|
let header_div = document.querySelector('div.reveal-header');
|
||||||
|
|
||||||
|
if(Reveal.getCurrentSlide().id == 'title-slide' ||
|
||||||
|
Reveal.getCurrentSlide().classList.contains('title-slide') || h2_text == ''
|
||||||
|
) {
|
||||||
|
header_div.style.visibility = 'hidden';
|
||||||
|
} else {
|
||||||
|
header_div.style.visibility = 'visible';
|
||||||
|
header_title_placeholder.style.color = 'white';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function linkify_logo(logo, href) {
|
||||||
|
const logo_cloned = logo.cloneNode(true);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = href;
|
||||||
|
link.target = '_blank';
|
||||||
|
link.appendChild(logo_cloned);
|
||||||
|
logo.replaceWith(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
function get_clean_attrs(elem, attrName) {
|
||||||
|
let attrVal = elem.getAttribute(attrName);
|
||||||
|
if (attrVal != null) {
|
||||||
|
elem.removeAttribute(attrName);
|
||||||
|
}
|
||||||
|
return attrVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (Reveal.isReady()) {
|
||||||
|
add_header();
|
||||||
|
|
||||||
|
const slides = Reveal.getSlides();
|
||||||
|
slides.forEach(slide => {
|
||||||
|
const h2Element = slide.querySelector('h2');
|
||||||
|
|
||||||
|
if (h2Element) {
|
||||||
|
h2Element.style.display = 'none';
|
||||||
|
const h2Text = h2Element.textContent;
|
||||||
|
slide.setAttribute('data-h2-text', h2Text);
|
||||||
|
} else {
|
||||||
|
slide.setAttribute('data-h2-text', '');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
make_h2_title();
|
||||||
|
|
||||||
|
/*************** linkifying the header and footer logo ********************/
|
||||||
|
const header_logo = document.querySelector('div.header-logo');
|
||||||
|
if (header_logo != null) {
|
||||||
|
const header_logo_link = get_clean_attrs(header_logo, 'data-header-logo-link');
|
||||||
|
const footer_logo_link = get_clean_attrs(header_logo, 'data-footer-logo-link');
|
||||||
|
|
||||||
|
if (header_logo_link != null) {
|
||||||
|
const header_logo_img = document.querySelector('div.header-logo').firstElementChild;
|
||||||
|
linkify_logo(header_logo_img, header_logo_link);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
/****************************** END ***************************************/
|
||||||
|
|
||||||
|
Reveal.on( 'slidechanged', event => {
|
||||||
|
make_h2_title();
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener("load", (event) => {
|
||||||
|
header();
|
||||||
|
});
|
63
default.nix
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
let
|
||||||
|
inputs = import ./deps;
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = import inputs.nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
pre-commit-hook = (import inputs."git-hooks.nix").run {
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
hooks = {
|
||||||
|
statix.enable = true;
|
||||||
|
deadnix.enable = true;
|
||||||
|
rfc101 = {
|
||||||
|
enable = true;
|
||||||
|
name = "RFC-101 formatting";
|
||||||
|
entry = "${pkgs.lib.getExe pkgs.nixfmt-rfc-style}";
|
||||||
|
files = "\\.nix$";
|
||||||
|
};
|
||||||
|
commitizen.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
|
||||||
|
rec {
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = [ pkgs.bashInteractive ];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
quarto
|
||||||
|
texliveFull
|
||||||
|
jose
|
||||||
|
clevis
|
||||||
|
jq
|
||||||
|
];
|
||||||
|
shellHook = ''
|
||||||
|
${pre-commit-hook.shellHook}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.x86_64-linux = {
|
||||||
|
website = pkgs.callPackage (
|
||||||
|
{ stdenv, quarto, ... }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "fosdem24-clevis";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
buildInputs = [ quarto ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
mkdir _slides
|
||||||
|
HOME=. quarto render index.qmd --to revealjs --output-dir _slides
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
cp -r _slides $out
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
checks.default = {
|
||||||
|
inherit packages;
|
||||||
|
};
|
||||||
|
}
|
79
deps/default.nix
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# Generated by npins. Do not modify; will be overwritten regularly
|
||||||
|
let
|
||||||
|
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||||
|
inherit (data) version;
|
||||||
|
|
||||||
|
mkSource =
|
||||||
|
spec:
|
||||||
|
assert spec ? type;
|
||||||
|
let
|
||||||
|
path =
|
||||||
|
if spec.type == "Git" then
|
||||||
|
mkGitSource spec
|
||||||
|
else if spec.type == "GitRelease" then
|
||||||
|
mkGitSource spec
|
||||||
|
else if spec.type == "PyPi" then
|
||||||
|
mkPyPiSource spec
|
||||||
|
else if spec.type == "Channel" then
|
||||||
|
mkChannelSource spec
|
||||||
|
else
|
||||||
|
builtins.throw "Unknown source type ${spec.type}";
|
||||||
|
in
|
||||||
|
spec // { outPath = path; };
|
||||||
|
|
||||||
|
mkGitSource =
|
||||||
|
{
|
||||||
|
repository,
|
||||||
|
revision,
|
||||||
|
url ? null,
|
||||||
|
hash,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
assert repository ? type;
|
||||||
|
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||||
|
# In the latter case, there we will always be an url to the tarball
|
||||||
|
if url != null then
|
||||||
|
(builtins.fetchTarball {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||||
|
})
|
||||||
|
else
|
||||||
|
assert repository.type == "Git";
|
||||||
|
let
|
||||||
|
urlToName =
|
||||||
|
url: rev:
|
||||||
|
let
|
||||||
|
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
|
||||||
|
|
||||||
|
short = builtins.substring 0 7 rev;
|
||||||
|
|
||||||
|
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||||
|
in
|
||||||
|
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||||
|
name = urlToName repository.url revision;
|
||||||
|
in
|
||||||
|
builtins.fetchGit {
|
||||||
|
inherit (repository) url;
|
||||||
|
rev = revision;
|
||||||
|
inherit name;
|
||||||
|
# hash = hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkPyPiSource =
|
||||||
|
{ url, hash, ... }:
|
||||||
|
builtins.fetchurl {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkChannelSource =
|
||||||
|
{ url, hash, ... }:
|
||||||
|
builtins.fetchTarball {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
if version == 3 then
|
||||||
|
builtins.mapAttrs (_: mkSource) data.pins
|
||||||
|
else
|
||||||
|
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
23
deps/sources.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"pins": {
|
||||||
|
"git-hooks.nix": {
|
||||||
|
"type": "Git",
|
||||||
|
"repository": {
|
||||||
|
"type": "GitHub",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix"
|
||||||
|
},
|
||||||
|
"branch": "master",
|
||||||
|
"revision": "f451c19376071a90d8c58ab1a953c6e9840527fd",
|
||||||
|
"url": "https://github.com/cachix/git-hooks.nix/archive/f451c19376071a90d8c58ab1a953c6e9840527fd.tar.gz",
|
||||||
|
"hash": "1gdkg3bcxqzccb7gzp2gvbwjk7lnv3p9sl10113z9dnmn6bx8lz8"
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"type": "Channel",
|
||||||
|
"name": "nixpkgs-unstable",
|
||||||
|
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre658316.e36e9f57337d/nixexprs.tar.xz",
|
||||||
|
"hash": "0z1dl3aaxhia642i9xfv571r040axkbm1zyxylgmhsqkra5lxk8z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": 3
|
||||||
|
}
|
BIN
diffoscope-heuristics.png
Normal file
After Width: | Height: | Size: 608 KiB |
BIN
diffoscope.png
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
ecosystems.png
Normal file
After Width: | Height: | Size: 831 KiB |
BIN
env.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
eval-build.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
evolution-heuristics.png
Normal file
After Width: | Height: | Size: 594 KiB |
BIN
graph.png
Normal file
After Width: | Height: | Size: 468 KiB |
BIN
homepage.jpg
Normal file
After Width: | Height: | Size: 428 KiB |
BIN
icse.jpeg
Normal file
After Width: | Height: | Size: 670 KiB |
593
index.qmd
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
---
|
||||||
|
title: Reproducibility in functional package management
|
||||||
|
date: 2025-2-11
|
||||||
|
date-format: long
|
||||||
|
lightbox: true
|
||||||
|
logo: telecom.png
|
||||||
|
margin-top: "0px"
|
||||||
|
author:
|
||||||
|
- name:
|
||||||
|
given: Julien
|
||||||
|
family: Malka
|
||||||
|
url: https://luj.fr
|
||||||
|
email: julien.malka@telecom-paris.fr
|
||||||
|
orcid: 0009-0008-9845-6300
|
||||||
|
roles:
|
||||||
|
- conceptualization
|
||||||
|
- investigation
|
||||||
|
- writing – original draft
|
||||||
|
affiliations:
|
||||||
|
- id: telecom
|
||||||
|
name: Télécom Paris, Institut Polytechnique de Paris
|
||||||
|
fig-align: center
|
||||||
|
code-overflow: wrap
|
||||||
|
code-line-numbers: false
|
||||||
|
css: styles.css
|
||||||
|
|
||||||
|
format:
|
||||||
|
metropolis-beamer-revealjs:
|
||||||
|
theme: slide.scss
|
||||||
|
toc: false
|
||||||
|
toc-title: Plan
|
||||||
|
toc-depth: 2
|
||||||
|
slide-level: 2
|
||||||
|
slide-number: true
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Research topics
|
||||||
|
|
||||||
|
**Main topics:** Cybersecurity & Software engineering
|
||||||
|
|
||||||
|
*How can one trust the software installed on one’s system is not malicious?*
|
||||||
|
|
||||||
|
- What if we make the assumption that the software is **open source**?
|
||||||
|
|
||||||
|
## Software supply chain
|
||||||
|
|
||||||
|
::: {.r-fit-text}
|
||||||
|
|
||||||
|
**Definition:** All the **components**, **tools** and **processes** used to **produce**, **compile** and **distribute** software.
|
||||||
|
|
||||||
|
- An increasing number of attacks that target the software supply chain of the software instead of the software itself : for example *Solarwinds* (2020).
|
||||||
|
- Will to create security norms of the software supply chain (*USA Executive order on improving the nation’s cybersecurity*/*EU Cyber Resilience Act*).
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-eval-build}
|
||||||
|
{.r-stretch}
|
||||||
|
|
||||||
|
Software supply chain overview ([slsa.dev](https://slsa.dev))
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Main PhD research question
|
||||||
|
|
||||||
|
How to increase trust in the Open Source Software Supply Chain with **functional package managers** and **reproducible builds**?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Functional package managers {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
New software deployment model (from which **Nix** has been the first example).
|
||||||
|
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ stdenv, lib, fetchFromGitHub }:
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functional package managers {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
New software deployment model (from which **Nix** has been the first example).
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ stdenv, lib, fetchFromGitHub }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
version = "1.3.7";
|
||||||
|
pname = "htpdate";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "twekkel";
|
||||||
|
repo = pname;
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-X7r95Uc4oGB0eVum5D7pC4tebZIyyz73g6Q/D0cjuFM=";
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functional package managers {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
New software deployment model (from which **Nix** has been the first example).
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ stdenv, lib, fetchFromGitHub }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
version = "1.3.7";
|
||||||
|
pname = "htpdate";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "twekkel";
|
||||||
|
repo = pname;
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-X7r95Uc4oGB0eVum5D7pC4tebZIyyz73g6Q/D0cjuFM=";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeFlags = [
|
||||||
|
"prefix=$(out)"
|
||||||
|
];
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functional package managers {auto-animate="true"}
|
||||||
|
|
||||||
|
::: {.r-fit-text}
|
||||||
|
|
||||||
|
New software deployment model (from which **Nix** has been the first example).
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ stdenv, lib, fetchFromGitHub }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
version = "1.3.7";
|
||||||
|
pname = "htpdate";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "twekkel";
|
||||||
|
repo = pname;
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-X7r95Uc4oGB0eVum5D7pC4tebZIyyz73g6Q/D0cjuFM=";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeFlags = [
|
||||||
|
"prefix=$(out)"
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Utility to fetch time and set the system clock over HTTP";
|
||||||
|
platforms = platforms.linux;
|
||||||
|
license = licenses.gpl2Plus;
|
||||||
|
maintainers = with maintainers; [ julienmalka ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## Evaluation->Build pipeline
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-eval-build}
|
||||||
|
{.r-stretch}
|
||||||
|
|
||||||
|
Eval-build pipeline
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## Functional package managers for SSC security
|
||||||
|
|
||||||
|
Functional package managers also have interesting properties for software supply chain security (which are of interest for us):
|
||||||
|
|
||||||
|
- Builds from source;
|
||||||
|
- Sandboxed compilation.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Functional package managers for SSC security
|
||||||
|
|
||||||
|
- Installed packages create a static graph structure (a Merkle tree) that can be analysed in order to find known vulnerability in the dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-eval-build}
|
||||||
|
{.r-stretch}
|
||||||
|
|
||||||
|
Example of a package dependency graph
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Binary distribution
|
||||||
|
|
||||||
|
- It is not always reasonable to compile all the software a user wants to install on their own machine: creates the necessity of binary caches ;
|
||||||
|
- **But** binary caches make us lose some of the interesting security properties of functional package managers.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Reproducible builds {.lol}
|
||||||
|
|
||||||
|
{height='4em' fig-align="center"}
|
||||||
|
|
||||||
|
A build is **reproducible** if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.
|
||||||
|
|
||||||
|
|
||||||
|
## Why is build reproducibility important?
|
||||||
|
|
||||||
|
::: {#fig-rb}
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Leveraging reproducible-builds to increase trust in distributed artifacts.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Research questions {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
**How reproducible is software in the functional package management model?**
|
||||||
|
|
||||||
|
- Is Nix evaluation reproducible? Can we reproduce *build environments* of Nix packages?
|
||||||
|
- Do functional package management enable **bitwise build reproducibility**?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Reproducibility of build environments {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
- Is Nix evaluation reproducible? Can we reproduce *build environments* of Nix packages?
|
||||||
|
|
||||||
|
:::: {.columns}
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
{height='14em'}
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
**"Reproducibility of Build Environments through Space and Time"**, ICSE 2024 (New Ideas and Emerging Results track), *J. Malka, S. Zacchiroli, T. Zimmermann*.
|
||||||
|
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Reproducibility of build environments
|
||||||
|
|
||||||
|
|
||||||
|
We say that two build environments are identical if they contain the **exact same set of executables, up to their specific versions**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Reproducibility in Space
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-rb}
|
||||||
|

|
||||||
|
|
||||||
|
Reproducibility of build environments in Space
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Reproducibility in Time
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-rb}
|
||||||
|
{.r-stretch}
|
||||||
|
|
||||||
|
Reproducibility of build environments in Time
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## Research questions
|
||||||
|
|
||||||
|
|
||||||
|
::: {.incremental}
|
||||||
|
- **RQ1:** Is space and time reproducibility of build environments achievable with Nix ?
|
||||||
|
- **RQ2:** Does it allow rebuilding of past software versions ?
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Experimental protocol
|
||||||
|
|
||||||
|
::: {.incremental}
|
||||||
|
|
||||||
|
1) Sample 200 revisions of the Nix software repository, picked from 2017 to 2023;
|
||||||
|
2) For each sampled revision, perform the **evaluation** of each package and compare with the historical truth (historical CI results);
|
||||||
|
3) For the *oldest revision* of our samples, perform the **build** of each package and compare with the historical truth.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## Results {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
**RQ1:** *Reproducibility of build environments*
|
||||||
|
|
||||||
|
- We were able to **reproduce the build environment of 99.99% of the packages** we tested;
|
||||||
|
- Discrepancies we found were due to the (unfortunate) use of some of Nix’s impure builtins.
|
||||||
|
|
||||||
|
## Results {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
**RQ1:** *Reproducibility of build environments*
|
||||||
|
|
||||||
|
- We were able to **reproduce the build environment of 99.99% of the packages** we tested;
|
||||||
|
- Discrepancies we found were due to the (unfortunate) use of some of Nix’s impure builtins.
|
||||||
|
|
||||||
|
**RQ2:** *Rebuilding past software versions*
|
||||||
|
|
||||||
|
- We were able to **build successfully 14233 out of the 14242 (99.94%) packages that were built successfully by CI in 2017**;
|
||||||
|
- Discrepancies we found were due to leakages of the Nix build sandbox, that we wish to investigate further.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Research questions {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
**How reproducible is software in the functional package management model?**
|
||||||
|
|
||||||
|
- Is Nix evaluation reproducible? Can we reproduce *build environments* of Nix packages?
|
||||||
|
- Do functional package management enable **bitwise build reproducibility**?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Reproducibility of build environments {auto-animate="true"}
|
||||||
|
|
||||||
|
|
||||||
|
- Do functional package management enable **bitwise build reproducibility**?
|
||||||
|
|
||||||
|
:::: {.columns}
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
{height='14em'}
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
**"Does Functional Package Management Enable Reproducible Builds at Scale? Yes."**, MSR 2025, *J. Malka, S. Zacchiroli, T. Zimmermann*.
|
||||||
|
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Nix **does not** garantee reproducible builds!
|
||||||
|
|
||||||
|
```nix
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> { };
|
||||||
|
in
|
||||||
|
pkgs.runCommand "random" { } ''
|
||||||
|
echo $RANDOM > $out
|
||||||
|
''
|
||||||
|
```
|
||||||
|
|
||||||
|
```{mermaid}
|
||||||
|
flowchart TD
|
||||||
|
A[nix-build]
|
||||||
|
A --run 1--> B[12505]
|
||||||
|
A --run 2--> C[29217]
|
||||||
|
```
|
||||||
|
|
||||||
|
→ Will produce an artifact with a different number at each run!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## So how reproducible packages of the Nix distribution are?
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-monitoring}
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[https://reproducible.nixos.org](https://reproducible.nixos.org)
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## So how reproducible packages of the Nix distribution are?
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-diffoscope}
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Example of a diffoscope.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
**Problem:**
|
||||||
|
|
||||||
|
- Only monitors a small subset of `nixpkgs` (~1300 packages for the Gnome image runtime closure)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Research questions
|
||||||
|
|
||||||
|
- **RQ1:** What is the evolution of bitwise reproducible packages in `nixpkgs` between 2017 and 2023?
|
||||||
|
- **RQ2:** What are the unreproducible packages?
|
||||||
|
- **RQ3:** Why are packages unreproducible?
|
||||||
|
- **RQ4:** How are unreproducibilities fixed?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Research methodology
|
||||||
|
|
||||||
|
::: {#fig-methodology}
|
||||||
|
{fig-align="center"}
|
||||||
|
|
||||||
|
Pipeline summarizing our research methodology.
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## A few figures
|
||||||
|
|
||||||
|
::::{.columns}
|
||||||
|
|
||||||
|
::: {.column width="60%"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-diffoscope}
|
||||||
|

|
||||||
|
|
||||||
|
Evolution of the size of the nine most popular software ecosystems in `nixpkgs`.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
::: {.column width="40%"}
|
||||||
|
- 709 816 packages built;
|
||||||
|
- 14 296 total build hours;
|
||||||
|
- 548 390 tracked by name and corresponding to <span style="white-space: nowrap;">59 103</span> unique packages associated to a specific software ecossytem .
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## RQ1: Evolution of bitwise reproducible packages
|
||||||
|
|
||||||
|
::: {#fig-overall}
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Proportion of reproducible, rebuildable and non-rebuildable packages over time.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## RQ1: Evolution of bitwise reproducible packages
|
||||||
|
|
||||||
|
::: {#fig-overall2}
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Absolute numbers of reproducible, rebuildable and non-rebuildable packages over time.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## RQ1: Evolution of bitwise reproducible packages
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-overall2-reg}
|
||||||
|
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Reproducibility regression around June 2020.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## RQ2: What are the unreproducible packages?
|
||||||
|
|
||||||
|
::: {#fig-diff}
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Proportion of reproducible packages belonging to the three most popular ecosystems and the base namespace of nixpkgs.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## RQ3: Why are packages unreproducible?
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-diff}
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Evolution of the number of packages that are matched by each of our heuristics, over time.
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## RQ4: How are unreproducibilities fixed?
|
||||||
|
|
||||||
|
|
||||||
|
- Sampled 100 fixes in our dataset of reproducibility fixed (obtained by bisection of the `nixpkgs` repository):
|
||||||
|
|
||||||
|
→ **In 93 instances, "reproducibility" was not mentionned on the pull request / commit message.**
|
||||||
|
|
||||||
|
→ **In 75 cases the fix was merely a package update.**
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
- Studied the 15 most impactful fixes (from 3052 to 27 packages fixed):
|
||||||
|
|
||||||
|
→ **In 8/15 instances, the reproducibility issue being fixed is documented.**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
- Bitwise reproducibility in `nixpkgs` as of 2023: 91%;
|
||||||
|
- This justifies investing resources/conducting research on distributed cache solutions relying on build reproducibility.
|
||||||
|
|
||||||
|
|
||||||
|
## Thank you for your attention!
|
||||||
|
|
||||||
|
|
||||||
|
<h3><ins>My socials:</ins></h3>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="margin-bottom: 40px;"></div>
|
||||||
|
{{< bi mastodon >}} luj@chaos.social
|
||||||
|
|
||||||
|
{{< bi envelope >}} julien.malka@telecom-paris.fr
|
||||||
|
|
||||||
|
|
||||||
|
:::: {.columns}
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
|
||||||
|
{height='11em'}
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
::: {.column width="50%"}
|
||||||
|
|
||||||
|
{height='11em'}
|
||||||
|
:::
|
||||||
|
|
||||||
|
::::
|
||||||
|
|
||||||
|
## RQ1: Evolution of bitwise reproducible packages
|
||||||
|
|
||||||
|
|
||||||
|
::: {#fig-overall2-reg}
|
||||||
|
|
||||||
|
|
||||||
|
{.r-stretch fig-align="center"}
|
||||||
|
|
||||||
|
Sankey graph of the average flow of packages between two revisions, excluding the revision from June 2020, considered as an outlier.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
mastodon.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
minimal-iso-reproducibility.png
Normal file
After Width: | Height: | Size: 543 KiB |
BIN
monitoring.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
msr.jpeg
Normal file
After Width: | Height: | Size: 656 KiB |
BIN
msr.png
Normal file
After Width: | Height: | Size: 236 KiB |
BIN
pipeline.png
Normal file
After Width: | Height: | Size: 651 KiB |
BIN
pipelinev2.png
Normal file
After Width: | Height: | Size: 1,020 KiB |
BIN
qr-icse.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
qr-msr.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
qr.png
Normal file
After Width: | Height: | Size: 380 KiB |
BIN
rb-verif(1).png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
rb-verif.png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
rb.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
reproducibility-ecosystems.png
Normal file
After Width: | Height: | Size: 578 KiB |
BIN
reproducibility-overall-absolute-reg.png
Normal file
After Width: | Height: | Size: 714 KiB |
BIN
reproducibility-overall-absolute.png
Normal file
After Width: | Height: | Size: 503 KiB |
BIN
reproducibility-overall-relative.png
Normal file
After Width: | Height: | Size: 456 KiB |
BIN
sankey-average.png
Normal file
After Width: | Height: | Size: 452 KiB |
1
shell.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(import ./.).devShells.default
|
2
slide.scss
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/*-- scss:defaults --*/
|
||||||
|
$presentation-h-font12: "Cantarell";
|
BIN
software_supply_chain.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
space.png
Normal file
After Width: | Height: | Size: 132 KiB |
23
styles.css
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#fig-nixos {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-number {
|
||||||
|
color: darkgrey !important;
|
||||||
|
font-size: 0.6em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reveal .slide-logo {
|
||||||
|
height: 11% !important;
|
||||||
|
max-width: unset !important;
|
||||||
|
max-height: unset !important;
|
||||||
|
}
|
BIN
telecom.png
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
telecom_paristech.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
time.png
Normal file
After Width: | Height: | Size: 139 KiB |