pub mod archive;
pub mod contents;
pub mod error;
pub mod middleware;
pub mod pagination;
pub mod rate_limit;
pub mod release;
pub mod ssh_key;
pub mod store;
pub mod token;
pub mod user;
pub use archive::{create_archive, ArchiveEntry, ArchiveFormat, TarGzBuilder, ZipBuilder};
pub use contents::{
base64_encode, detect_spdx_id, is_readme_file, recognize_license_file, ContentEntry,
ContentType, ContentsQuery, LicenseResponse, ReadmeResponse,
};
pub use error::{CompatError, Result};
pub use middleware::{
parse_authorization_header, resource_from_path, AuthContext, AuthorizationValue, ErrorResponse,
ResponseHeaders, ValidationError, ValidationErrorCode,
};
pub use pagination::{
paginate, PaginatedResponse, PaginationLinks, PaginationParams, DEFAULT_PER_PAGE, MAX_PER_PAGE,
};
pub use rate_limit::{
RateLimitHeaders, RateLimitInfo, RateLimitResource, RateLimitResources, RateLimitResponse,
RateLimitState, RateLimiter, DEFAULT_RATE_LIMIT, UNAUTHENTICATED_RATE_LIMIT,
};
pub use release::{
AssetId, AssetResponse, AuthorInfo, CreateReleaseRequest, Release, ReleaseAsset, ReleaseId,
ReleaseResponse, UpdateReleaseRequest,
};
pub use ssh_key::{AddSshKeyRequest, SshKey, SshKeyId, SshKeyResponse, SshKeyType};
pub use store::{CompatStats, CompatStore, ReleaseStore, SshKeyStore, TokenStore, UserStore};
pub use token::{
CreateTokenRequest, PersonalAccessToken, TokenId, TokenResponse, TokenScope, TokenValue,
};
pub use user::{CreateUserRequest, UpdateUserRequest, User, UserId, UserProfile};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_public_api() {
let store = CompatStore::new();
assert_eq!(store.users.count(), 0);
assert_eq!(store.tokens.count(), 0);
}
#[test]
fn test_full_user_token_flow() {
let store = CompatStore::new();
let user = store
.users
.create("alice".to_string(), "pubkey123".to_string())
.unwrap();
assert_eq!(user.username, "alice");
let (token, plaintext) = store
.tokens
.create(
user.id,
"My Token".to_string(),
vec![TokenScope::RepoRead, TokenScope::RepoWrite],
None,
)
.unwrap();
assert!(plaintext.starts_with("guts_"));
let (user_id, scopes) = store.tokens.verify(&plaintext).unwrap();
assert_eq!(user_id, user.id);
assert!(scopes.contains(&TokenScope::RepoRead));
assert!(scopes.contains(&TokenScope::RepoWrite));
assert!(token.has_scope(TokenScope::RepoRead));
assert!(token.has_scope(TokenScope::RepoWrite));
assert!(!token.has_scope(TokenScope::Admin));
}
#[test]
fn test_rate_limiting() {
let limiter = RateLimiter::new();
let state = limiter.get_state("user1", RateLimitResource::Core, true);
assert_eq!(state.limit, 5000);
let state = limiter.get_state("anon", RateLimitResource::Core, false);
assert_eq!(state.limit, 60);
}
#[test]
fn test_pagination() {
let items: Vec<i32> = (1..=100).collect();
let params = PaginationParams::new(2, 10);
let response = paginate(&items, ¶ms);
assert_eq!(response.items.len(), 10);
assert_eq!(response.total_count, 100);
assert_eq!(response.page, 2);
assert!(response.has_next_page());
assert!(response.has_prev_page());
}
#[test]
fn test_release_management() {
let store = CompatStore::new();
let release = store
.releases
.create(
"alice/repo".to_string(),
"v1.0.0".to_string(),
"main".to_string(),
"alice".to_string(),
)
.unwrap();
let asset = store
.releases
.add_asset(
release.id,
"app-linux-amd64.tar.gz".to_string(),
"application/gzip".to_string(),
b"binary content".to_vec(),
"alice".to_string(),
)
.unwrap();
assert_eq!(asset.name, "app-linux-amd64.tar.gz");
let content = store.releases.get_asset_content(&asset.content_hash);
assert!(content.is_some());
}
#[test]
fn test_archive_generation() {
let entries = vec![
ArchiveEntry::file("README.md".to_string(), b"# My Project".to_vec()),
ArchiveEntry::file("src/main.rs".to_string(), b"fn main() {}".to_vec()),
];
let archive = create_archive(
ArchiveFormat::TarGz,
"my-project-v1.0.0".to_string(),
entries,
);
assert!(archive.is_ok());
}
#[test]
fn test_ssh_key_management() {
let store = CompatStore::new();
let key = store.ssh_keys.add(
1,
"My Laptop".to_string(),
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl user@laptop".to_string(),
).unwrap();
assert!(key.fingerprint.starts_with("SHA256:"));
assert_eq!(key.key_type, SshKeyType::Ed25519);
let keys = store.ssh_keys.list_for_user(1);
assert_eq!(keys.len(), 1);
}
}