From 45df4d0d9b577fecee798d672695fe24ff57fb1b Mon Sep 17 00:00:00 2001 From: mo khan Date: Tue, 15 Jul 2025 16:37:08 -0600 Subject: feat: migrate from Cedar to SpiceDB authorization system This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema. --- vendor/android-tzdata/src/lib.rs | 29 ------- vendor/android-tzdata/src/tzdata.rs | 166 ------------------------------------ 2 files changed, 195 deletions(-) delete mode 100644 vendor/android-tzdata/src/lib.rs delete mode 100644 vendor/android-tzdata/src/tzdata.rs (limited to 'vendor/android-tzdata/src') diff --git a/vendor/android-tzdata/src/lib.rs b/vendor/android-tzdata/src/lib.rs deleted file mode 100644 index b6b0e36c..00000000 --- a/vendor/android-tzdata/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Parser for the Android-specific tzdata file. - -mod tzdata; - -/// Tries to locate the `tzdata` file, parse it, and return the entry for the -/// requested time zone. -/// -/// # Errors -/// -/// Returns an [std::io::Error] if the `tzdata` file cannot be found and parsed, or -/// if it does not contain the requested timezone entry. -/// -/// # Example -/// -/// ```rust -/// # use std::error::Error; -/// # use android_tzdata::find_tz_data; -/// # -/// # fn main() -> Result<(), Box> { -/// let tz_data = find_tz_data("Europe/Kiev")?; -/// // Check it's version 2 of the [Time Zone Information Format](https://www.ietf.org/archive/id/draft-murchison-rfc8536bis-02.html). -/// assert!(tz_data.starts_with(b"TZif2")); -/// # Ok(()) -/// # } -/// ``` -pub fn find_tz_data(tz_name: impl AsRef) -> Result, std::io::Error> { - let mut file = tzdata::find_file()?; - tzdata::find_tz_data_in_file(&mut file, tz_name.as_ref()) -} diff --git a/vendor/android-tzdata/src/tzdata.rs b/vendor/android-tzdata/src/tzdata.rs deleted file mode 100644 index 92e4b621..00000000 --- a/vendor/android-tzdata/src/tzdata.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Logic was mainly ported from https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/util/ZoneInfoDB.java - -use core::{cmp::Ordering, convert::TryInto}; -use std::{ - fs::File, - io::{self, ErrorKind, Read, Seek, SeekFrom}, -}; - -// The database uses 32-bit (4 byte) integers. -const TZ_INT_SIZE: usize = 4; -// The first 12 bytes contain a special version string. -const MAGIC_SIZE: usize = 12; -const HEADER_SIZE: usize = MAGIC_SIZE + 3 * TZ_INT_SIZE; -// The database reserves 40 bytes for each id. -const TZ_NAME_SIZE: usize = 40; -const INDEX_ENTRY_SIZE: usize = TZ_NAME_SIZE + 3 * TZ_INT_SIZE; -const TZDATA_LOCATIONS: [TzdataLocation; 2] = [ - TzdataLocation { - env_var: "ANDROID_DATA", - path: "/misc/zoneinfo/", - }, - TzdataLocation { - env_var: "ANDROID_ROOT", - path: "/usr/share/zoneinfo/", - }, -]; - -#[derive(Debug)] -struct TzdataLocation { - env_var: &'static str, - path: &'static str, -} - -#[derive(Debug, Clone, Copy)] -struct Header { - index_offset: usize, - data_offset: usize, - _zonetab_offset: usize, -} - -#[derive(Debug)] -struct Index(Vec); - -#[derive(Debug, Clone, Copy)] -struct IndexEntry<'a> { - _name: &'a [u8], - offset: usize, - length: usize, - _raw_utc_offset: usize, -} - -pub(super) fn find_file() -> Result { - for location in &TZDATA_LOCATIONS { - if let Ok(env_value) = std::env::var(location.env_var) { - if let Ok(file) = File::open(format!("{}{}tzdata", env_value, location.path)) { - return Ok(file); - } - } - } - Err(io::Error::from(io::ErrorKind::NotFound)) -} - -pub(super) fn find_tz_data_in_file( - mut file: impl Read + Seek, - tz_name: &str, -) -> Result, io::Error> { - let header = Header::new(&mut file)?; - let index = Index::new(&mut file, header)?; - if let Some(entry) = index.find_entry(tz_name) { - file.seek(SeekFrom::Start((entry.offset + header.data_offset) as u64))?; - let mut tz_data = vec![0u8; entry.length]; - file.read_exact(&mut tz_data)?; - Ok(tz_data) - } else { - Err(io::Error::from(ErrorKind::NotFound)) - } -} - -impl Header { - fn new(mut file: impl Read + Seek) -> Result { - let mut buf = [0; HEADER_SIZE]; - file.read_exact(&mut buf)?; - if !buf.starts_with(b"tzdata") || buf[MAGIC_SIZE - 1] != 0u8 { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "invalid magic number", - )); - } - Ok(Self { - index_offset: parse_tz_int(&buf, MAGIC_SIZE) as usize, - data_offset: parse_tz_int(&buf, MAGIC_SIZE + TZ_INT_SIZE) as usize, - _zonetab_offset: parse_tz_int(&buf, MAGIC_SIZE + 2 * TZ_INT_SIZE) as usize, - }) - } -} - -impl Index { - fn new(mut file: impl Read + Seek, header: Header) -> Result { - file.seek(SeekFrom::Start(header.index_offset as u64))?; - let size = header.data_offset - header.index_offset; - let mut bytes = vec![0; size]; - file.read_exact(&mut bytes)?; - Ok(Self(bytes)) - } - - fn find_entry(&self, name: &str) -> Option { - let name_bytes = name.as_bytes(); - let name_len = name_bytes.len(); - if name_len > TZ_NAME_SIZE { - return None; - } - - let zeros = [0u8; TZ_NAME_SIZE]; - let cmp = |chunk: &&[u8]| -> Ordering { - // tz names always have TZ_NAME_SIZE bytes and are right-padded with 0s - // so we check that a chunk starts with `name` and the remaining bytes are 0 - chunk[..name_len] - .cmp(name_bytes) - .then_with(|| chunk[name_len..TZ_NAME_SIZE].cmp(&zeros[name_len..])) - }; - - let chunks: Vec<_> = self.0.chunks_exact(INDEX_ENTRY_SIZE).collect(); - chunks - .binary_search_by(cmp) - .map(|idx| IndexEntry::new(chunks[idx])) - .ok() - } -} - -impl<'a> IndexEntry<'a> { - fn new(bytes: &'a [u8]) -> Self { - Self { - _name: bytes[..TZ_NAME_SIZE] - .splitn(2, |&b| b == 0u8) - .next() - .unwrap(), - offset: parse_tz_int(bytes, TZ_NAME_SIZE) as usize, - length: parse_tz_int(bytes, TZ_NAME_SIZE + TZ_INT_SIZE) as usize, - _raw_utc_offset: parse_tz_int(bytes, TZ_NAME_SIZE + 2 * TZ_INT_SIZE) as usize, - } - } -} - -/// Panics if slice does not contain [TZ_INT_SIZE] bytes beginning at start. -fn parse_tz_int(slice: &[u8], start: usize) -> u32 { - u32::from_be_bytes(slice[start..start + TZ_INT_SIZE].try_into().unwrap()) -} - -#[cfg(test)] -mod test { - use super::*; - use std::fs::File; - use std::io::Cursor; - - #[test] - fn parse() { - let mut archive = File::open("tests/resources/tzdata.zip").unwrap(); - let mut zip = zip::ZipArchive::new(&mut archive).unwrap(); - let mut file = zip.by_index(0).unwrap(); - let mut data = Vec::new(); - file.read_to_end(&mut data).unwrap(); - let cursor = Cursor::new(data); - let tz = find_tz_data_in_file(cursor, "Europe/Kiev").unwrap(); - assert!(tz.starts_with(b"TZif2")); - } -} -- cgit v1.2.3