Skip to content
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/cli/src/commands/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ impl Options {
&url_builder,
// Don't use strict mode in production yet
false,
// Don't stabilise in production
false,
)
.await?;
shutdown.register_reloadable(&templates);
Expand Down
29 changes: 23 additions & 6 deletions crates/cli/src/commands/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{fmt::Write, process::ExitCode};

use anyhow::{Context as _, bail};
use camino::Utf8PathBuf;
use chrono::DateTime;
use clap::Parser;
use figment::Figment;
use mas_config::{
Expand All @@ -34,14 +35,20 @@ enum Subcommand {
/// The directory must either not exist or be empty.
#[arg(long = "out-dir")]
out_dir: Option<Utf8PathBuf>,

/// Attempt to remove 'unstable' template input data such as asset
/// hashes, in order to make renders more reproducible between
/// versions.
#[arg(long = "stabilise")]
stabilise: bool,
},
}

impl Options {
pub async fn run(self, figment: &Figment) -> anyhow::Result<ExitCode> {
use Subcommand as SC;
match self.subcommand {
SC::Check { out_dir } => {
SC::Check { out_dir, stabilise } => {
let _span = info_span!("cli.templates.check").entered();

let template_config = TemplatesConfig::extract_or_default(figment)
Expand All @@ -59,9 +66,17 @@ impl Options {
let captcha_config = CaptchaConfig::extract_or_default(figment)
.map_err(anyhow::Error::from_boxed)?;

let clock = SystemClock::default();
// XXX: we should disallow SeedableRng::from_entropy
let mut rng = rand_chacha::ChaChaRng::from_entropy();
let now = if stabilise {
DateTime::from_timestamp_secs(0).unwrap()
Copy link
Member

Choose a reason for hiding this comment

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

Could we use a more believable timestamp so that the IDs look like they are not all zeros?

} else {
SystemClock::default().now()
};
let rng = if stabilise {
rand_chacha::ChaChaRng::from_seed([42; 32])
} else {
// XXX: we should disallow SeedableRng::from_entropy
rand_chacha::ChaChaRng::from_entropy()
};
let url_builder =
mas_router::UrlBuilder::new("https://example.com/".parse()?, None, None);
let site_config = site_config_from_config(
Expand All @@ -75,11 +90,13 @@ impl Options {
let templates = templates_from_config(
&template_config,
&site_config,
&url_builder, // Use strict mode in template checks
&url_builder,
// Use strict mode in template checks
true,
stabilise,
)
.await?;
let all_renders = templates.check_render(clock.now(), &mut rng)?;
let all_renders = templates.check_render(now, &rng)?;

if let Some(out_dir) = out_dir {
// Save renders to disk.
Expand Down
2 changes: 2 additions & 0 deletions crates/cli/src/commands/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ impl Options {
&url_builder,
// Don't use strict mode on task workers for now
false,
// Don't stabilise in production
false,
)
.await?;

Expand Down
3 changes: 2 additions & 1 deletion crates/cli/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,12 @@ pub async fn templates_from_config(
site_config: &SiteConfig,
url_builder: &UrlBuilder,
strict: bool,
stabilise: bool,
) -> Result<Templates, anyhow::Error> {
Templates::load(
config.path.clone(),
url_builder.clone(),
config.assets_manifest.clone(),
(!stabilise).then(|| config.assets_manifest.clone()),
config.translations_path.clone(),
site_config.templates_branding(),
site_config.templates_features(),
Expand Down
2 changes: 1 addition & 1 deletion crates/handlers/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl TestState {
let templates = Templates::load(
workspace_root.join("templates"),
url_builder.clone(),
workspace_root.join("frontend/dist/manifest.json"),
Some(workspace_root.join("frontend/dist/manifest.json")),
workspace_root.join("translations"),
site_config.templates_branding(),
site_config.templates_features(),
Expand Down
42 changes: 42 additions & 0 deletions crates/spa/src/vite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,48 @@ pub struct Manifest {
inner: HashMap<Utf8PathBuf, ManifestEntry>,
}

impl Manifest {
/// Produce a sample manifest for use in reproducible sample renders.
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn sample() -> Self {
let mut inner = HashMap::new();

for name in &[
"src/shared.css",
"src/templates.css",
"src/main.tsx",
"src/swagger.ts",
] {
inner.insert(
name.parse().unwrap(),
ManifestEntry {
name: None,
names: None,
src: None,
// Construct a fake but slightly plausible dummy asset name.
file: name
.replace('/', "__")
.replace('.', "-XXXXX.")
.replace(".tsx", ".js")
.replace(".ts", ".js")
.parse()
.unwrap(),
css: None,
assets: None,
is_entry: None,
is_dynamic_entry: None,
imports: None,
dynamic_imports: None,
integrity: None,
},
);
}

Manifest { inner }
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum FileType {
Script,
Expand Down
3 changes: 3 additions & 0 deletions crates/templates/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ mas-i18n.workspace = true
mas-iana.workspace = true
mas-router.workspace = true
mas-spa.workspace = true

[dev-dependencies]
rand_chacha.workspace = true
Loading
Loading