Added OIDC workflow and Helm Chart
Checks / test (push) Failing after 4m13s

This commit is contained in:
Aleksandr Bogomiakov committed 2026-10-07 14:22:37 +01:00
1 parent 984c7083a1
commit 7afdc4be97
29 files changed
+872 -33

No files matched your search

+9
View File
@@ -508,6 +508,15 @@ workspaces:
assert!(config.bootstrap_usernames().is_empty());
}
#[test]
fn the_helm_chart_default_instance_configuration_is_valid() {
let values: serde_yaml_ng::Value =
serde_yaml_ng::from_str(include_str!("../helm/meguri/values.yaml")).unwrap();
let rendered = serde_yaml_ng::to_string(&values["instanceConfig"]).unwrap();
let config = Config::parse(&rendered).unwrap();
assert!(config.oidc.is_some() && !config.workspaces.is_empty());
}
#[test]
fn known_groups_are_unique_and_sorted_and_the_form_flags_follow_the_configuration() {
let c = config();
+16
View File
@@ -127,6 +127,9 @@ pub struct NewUser {
pub email: Option<String>,
#[serde(default)]
pub groups: Vec<String>,
/// Scheduling country (ISO 3166-1 alpha-2); defaults to CY like every new account.
#[serde(default)]
pub country: Option<String>,
}
/// Creates a password account. `actor` is None only for trusted startup seeding; the request
@@ -158,6 +161,19 @@ pub async fn create_password_user(
let hash = service::hash_password(input.password).await?;
let mut row = new_user_row(username.clone(), input.display_name, Some(hash));
row.email = email;
if let Some(country) = input
.country
.as_deref()
.map(str::trim)
.filter(|c| !c.is_empty())
{
let country = country.to_ascii_uppercase();
ensure(
crate::domain::valid_country(&country),
crate::i18n::text("err_choose_a_valid_country_code_e79c72"),
)?;
row.country = country;
}
match row.clone().insert(&db.db).await {
Ok(_) => {}
Err(cot::db::DatabaseError::UniqueViolation) => {
+21 -18
View File
@@ -14,21 +14,24 @@ CY,2026-10-28,Ohi Day
CY,2026-12-24,Christmas Eve
CY,2026-12-25,Christmas Day
CY,2026-12-26,Boxing Day
JP,2026-01-01,New Year's Day
JP,2026-01-12,Coming of Age Day
JP,2026-02-11,National Foundation Day
JP,2026-02-23,Emperor's Birthday
JP,2026-03-20,Vernal Equinox Day
JP,2026-04-29,Showa Day
JP,2026-05-03,Constitution Memorial Day
JP,2026-05-04,Greenery Day
JP,2026-05-05,Children's Day
JP,2026-05-06,Substitute Holiday
JP,2026-07-20,Marine Day
JP,2026-08-11,Mountain Day
JP,2026-09-21,Respect for the Aged Day
JP,2026-09-22,Citizens' Holiday
JP,2026-09-23,Autumnal Equinox Day
JP,2026-10-12,Sports Day
JP,2026-11-03,Culture Day
JP,2026-11-23,Labour Thanksgiving Day
GB,2026-01-01,New Year's Day
GB,2026-04-03,Good Friday
GB,2026-04-06,Easter Monday
GB,2026-05-04,Early May bank holiday
GB,2026-05-25,Spring bank holiday
GB,2026-08-31,Summer bank holiday
GB,2026-12-25,Christmas Day
GB,2026-12-28,Boxing Day (substitute day)
AM,2026-01-01,New Year's Day
AM,2026-01-02,New Year holiday
AM,2026-01-06,Christmas Day
AM,2026-01-28,Army Day
AM,2026-03-08,Women's Day
AM,2026-04-07,Motherhood and Beauty Day
AM,2026-04-24,Genocide Remembrance Day
AM,2026-05-01,Labour Day
AM,2026-05-09,Victory and Peace Day
AM,2026-05-28,Republic Day
AM,2026-07-05,Constitution Day
AM,2026-09-21,Independence Day
AM,2026-12-31,New Year's Eve
1 country date name
14 CY 2026-12-24 Christmas Eve
15 CY 2026-12-25 Christmas Day
16 CY 2026-12-26 Boxing Day
17 JP GB 2026-01-01 New Year's Day
18 JP GB 2026-01-12 2026-04-03 Coming of Age Day Good Friday
19 JP GB 2026-02-11 2026-04-06 National Foundation Day Easter Monday
20 JP GB 2026-02-23 2026-05-04 Emperor's Birthday Early May bank holiday
21 JP GB 2026-03-20 2026-05-25 Vernal Equinox Day Spring bank holiday
22 JP GB 2026-04-29 2026-08-31 Showa Day Summer bank holiday
23 JP GB 2026-05-03 2026-12-25 Constitution Memorial Day Christmas Day
24 JP GB 2026-05-04 2026-12-28 Greenery Day Boxing Day (substitute day)
25 JP AM 2026-05-05 2026-01-01 Children's Day New Year's Day
26 JP AM 2026-05-06 2026-01-02 Substitute Holiday New Year holiday
27 JP AM 2026-07-20 2026-01-06 Marine Day Christmas Day
28 JP AM 2026-08-11 2026-01-28 Mountain Day Army Day
29 JP AM 2026-09-21 2026-03-08 Respect for the Aged Day Women's Day
30 JP AM 2026-09-22 2026-04-07 Citizens' Holiday Motherhood and Beauty Day
31 JP AM 2026-09-23 2026-04-24 Autumnal Equinox Day Genocide Remembrance Day
32 JP AM 2026-10-12 2026-05-01 Sports Day Labour Day
33 JP AM 2026-11-03 2026-05-09 Culture Day Victory and Peace Day
34 JP AM 2026-11-23 2026-05-28 Labour Thanksgiving Day Republic Day
35 AM 2026-07-05 Constitution Day
36 AM 2026-09-21 Independence Day
37 AM 2026-12-31 New Year's Eve
+16 -9
View File
@@ -228,12 +228,14 @@ pub fn service_tiers(monday: NaiveDate, alice: Uuid, carol: Uuid) -> (Vec<Variab
}
/// Demonstration accounts: groups assigned exactly as an instance administrator would.
const ACCOUNTS: [(&str, &str, &str, &[&str]); 6] = [
("admin", "Instance Admin", "instance_admin", &[]),
/// Scheduling countries differ on purpose, so holiday handling is visible in the examples.
const ACCOUNTS: [(&str, &str, &str, &str, &[&str]); 6] = [
("admin", "Instance Admin", "instance_admin", "CY", &[]),
(
"alice",
"Alice Morgan",
"workspace_admin",
"CY",
&[
"acme-leads",
"support-leads",
@@ -245,16 +247,18 @@ const ACCOUNTS: [(&str, &str, &str, &[&str]); 6] = [
"bob",
"Bob Chen",
"employee",
"GB",
&["acme-staff", "regional-staff"],
),
(
"carol",
"Carol Davis",
"employee",
"AM",
&["acme-staff", "support-staff", "commerce-staff"],
),
("dave", "Dave Wilson", "employee", &["acme-staff"]),
("erin", "Erin Patel", "employee", &["acme-staff"]),
("dave", "Dave Wilson", "employee", "CY", &["acme-staff"]),
("erin", "Erin Patel", "employee", "GB", &["acme-staff"]),
];
/// `MEGURI_DEMO_SANDBOXES=n` (0-20) adds empty "Sandbox 1..n" workspaces, each with its own
@@ -285,10 +289,12 @@ pub fn config() -> Result<crate::access::Config> {
pub fn accounts() -> Vec<crate::demo_runtime::DemoAccount> {
ACCOUNTS
.iter()
.map(|(username, _, role, _)| crate::demo_runtime::DemoAccount {
username: (*username).into(),
role: (*role).into(),
})
.map(
|(username, _, role, _, _)| crate::demo_runtime::DemoAccount {
username: (*username).into(),
role: (*role).into(),
},
)
.collect()
}
@@ -315,7 +321,7 @@ pub async fn seed(db: &Store) -> Result<()> {
},
)
.await?;
for (username, display, _, groups) in ACCOUNTS {
for (username, display, _, country, groups) in ACCOUNTS {
let name = username.to_owned();
if query!(UserRow,$username==name).exists(&db.db).await? {
continue;
@@ -330,6 +336,7 @@ pub async fn seed(db: &Store) -> Result<()> {
password: notice.password.clone(),
email: None,
groups: groups.iter().map(|g| (*g).to_owned()).collect(),
country: Some(country.into()),
},
)
.await?;
+38
View File
@@ -104,6 +104,41 @@ pub async fn login(
Ok((user, token, csrf))
}
/// Employees with schedule-editing rights plan schedules, but the workspace preferences and the
/// scheduling directory belong to workspace administrators: name, planning horizon and every
/// existing person stay exactly as they were. New email contacts may be added while planning.
fn ensure_employee_edit(before: &WorkspaceDocument, after: &WorkspaceDocument) -> Result<()> {
let normal = |p: &Person| {
(
p.display_name.clone(),
p.email
.as_deref()
.map(|e| e.trim().to_lowercase())
.filter(|e| !e.is_empty()),
p.country
.as_deref()
.map(|c| c.trim().to_ascii_uppercase())
.filter(|c| !c.is_empty())
.unwrap_or_else(|| "CY".into()),
p.user_id,
)
};
let unchanged = after.name == before.name
&& after.horizon_days == before.horizon_days
&& before.people.iter().all(|old| {
after
.people
.iter()
.find(|p| p.id == old.id)
.is_some_and(|new| normal(new) == normal(old))
});
if unchanged {
Ok(())
} else {
Err(Error::Forbidden)
}
}
pub async fn update_document(
db: &Store,
actor: Uuid,
@@ -115,6 +150,9 @@ pub async fn update_document(
.prepare(workspace, revision, actor, Permission::EditSchedules)
.await?;
document.requests = record.document.requests.clone();
if db.owner(workspace, actor).await.is_err() {
ensure_employee_edit(&record.document, &document)?;
}
for request in &mut document.requests {
if request.status == RequestStatus::Pending
&& request