mirror of https://github.com/buster-so/buster.git
8.9 KiB
8.9 KiB
title | author | date | status | parent_prd | ticket |
---|---|---|---|---|---|
Public Sharing Parameters Fix | Claude | 2024-04-07 | Draft | project_bug_fixes_and_testing.md | BUS-1064 |
Public Sharing Parameters Fix
Problem Statement
The public sharing functionality is not properly handling sharing parameters, particularly in the context of asset visibility and access control. The current implementation has several issues:
Current behavior:
- Public sharing parameters are not properly validated
- Inconsistent handling of visibility settings
- Missing checks for valid sharing configurations
- Lack of proper error handling for invalid parameters
Expected behavior:
- Proper validation of all sharing parameters
- Consistent visibility handling
- Clear error messages for invalid configurations
- Proper access control enforcement
Goals
- Fix public sharing parameter validation
- Implement proper visibility checks
- Add comprehensive parameter validation
- Improve error handling
- Add tests for sharing scenarios
Non-Goals
- Adding new sharing features
- Modifying sharing UI
- Changing sharing model
- Adding new permission types
Technical Design
Overview
The fix involves updating the sharing parameter validation logic and implementing proper checks for visibility settings.
Parameter Validation
// libs/handlers/src/sharing/validate.rs
#[derive(Debug, Serialize, Deserialize)]
pub struct SharingParameters {
pub is_public: bool,
pub allow_anonymous: bool,
pub expiration: Option<DateTime<Utc>>,
pub access_level: AccessLevel,
}
impl SharingParameters {
pub fn validate(&self) -> Result<(), HandlerError> {
// Check for valid combinations
if self.is_public && !self.allow_anonymous {
return Err(HandlerError::BadRequest(
"Public sharing must allow anonymous access".to_string()
));
}
// Validate expiration
if let Some(exp) = self.expiration {
if exp < Utc::now() {
return Err(HandlerError::BadRequest(
"Expiration date must be in the future".to_string()
));
}
}
// Validate access level
if self.is_public && self.access_level > AccessLevel::ReadOnly {
return Err(HandlerError::BadRequest(
"Public sharing cannot grant write access".to_string()
));
}
Ok(())
}
}
Sharing Handler Update
// libs/handlers/src/sharing/update_sharing.rs
pub async fn update_sharing_handler(
asset_id: &Uuid,
user: &AuthenticatedUser,
params: SharingParameters,
) -> Result<Response, HandlerError> {
// Validate parameters
params.validate()?;
// Check user permissions
let asset = Asset::find_by_id(asset_id).await?;
if !user.can_manage_sharing(&asset) {
return Err(HandlerError::Forbidden(
"User does not have permission to update sharing settings".to_string()
));
}
// Update sharing settings
asset.update_sharing(params).await?;
Ok(Response::builder()
.status(StatusCode::OK)
.body(json!({"status": "success"}).to_string())
.unwrap())
}
Test Cases
// libs/handlers/tests/sharing/sharing_params_test.rs
#[tokio::test]
async fn test_invalid_public_sharing() -> Result<()> {
// Create test setup with admin user
let setup = TestSetup::new(Some(UserOrganizationRole::Admin)).await?;
let params = SharingParameters {
is_public: true,
allow_anonymous: false,
expiration: None,
access_level: AccessLevel::ReadOnly,
};
let result = params.validate();
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_expired_sharing() -> Result<()> {
// Create test setup with admin user
let setup = TestSetup::new(Some(UserOrganizationRole::Admin)).await?;
let params = SharingParameters {
is_public: true,
allow_anonymous: true,
expiration: Some(Utc::now() - Duration::hours(1)),
access_level: AccessLevel::ReadOnly,
};
let result = params.validate();
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_invalid_public_access() -> Result<()> {
// Create test setup with admin user
let setup = TestSetup::new(Some(UserOrganizationRole::Admin)).await?;
let params = SharingParameters {
is_public: true,
allow_anonymous: true,
expiration: None,
access_level: AccessLevel::ReadWrite,
};
let result = params.validate();
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_valid_sharing() -> Result<()> {
// Create test setup with admin user
let setup = TestSetup::new(Some(UserOrganizationRole::Admin)).await?;
// Create test asset
let asset_id = AssetTestHelpers::create_test_asset(
&setup.db,
"Test Asset",
setup.organization.id
).await?;
// Add owner permission
PermissionTestHelpers::create_permission(
&setup.db,
asset_id,
setup.user.id,
AssetPermissionRole::Owner
).await?;
let params = SharingParameters {
is_public: true,
allow_anonymous: true,
expiration: Some(Utc::now() + Duration::days(7)),
access_level: AccessLevel::ReadOnly,
};
let response = update_sharing_handler(
&asset_id,
&setup.user,
params.clone()
).await;
assert!(response.is_ok());
// Verify sharing settings in database
let mut conn = setup.db.diesel_conn().await?;
let sharing = sharing_settings::table
.filter(sharing_settings::asset_id.eq(asset_id))
.first::<SharingSettings>(&mut conn)
.await?;
assert_eq!(sharing.is_public, params.is_public);
assert_eq!(sharing.allow_anonymous, params.allow_anonymous);
assert_eq!(sharing.access_level, params.access_level);
assert_eq!(sharing.expiration, params.expiration);
Ok(())
}
#[tokio::test]
async fn test_sharing_update_history() -> Result<()> {
// Create test setup with admin user
let setup = TestSetup::new(Some(UserOrganizationRole::Admin)).await?;
// Create test asset
let asset_id = AssetTestHelpers::create_test_asset(
&setup.db,
"Test Asset",
setup.organization.id
).await?;
// Add owner permission
PermissionTestHelpers::create_permission(
&setup.db,
asset_id,
setup.user.id,
AssetPermissionRole::Owner
).await?;
let params = SharingParameters {
is_public: true,
allow_anonymous: true,
expiration: None,
access_level: AccessLevel::ReadOnly,
};
// Update sharing settings
update_sharing_handler(
&asset_id,
&setup.user,
params
).await?;
// Verify history entry in database
let mut conn = setup.db.diesel_conn().await?;
let history = sharing_history::table
.filter(sharing_history::asset_id.eq(asset_id))
.order_by(sharing_history::created_at.desc())
.first::<SharingHistory>(&mut conn)
.await?;
assert_eq!(history.user_id, setup.user.id);
assert_eq!(history.action, "update");
Ok(())
}
Dependencies
- Test infrastructure from Test Infrastructure Setup
- Existing sharing implementation
- Permission system
- Error handling system from HTTP Status Code Fix
Implementation Plan
Phase 1: Parameter Validation
- Implement parameter validation
- Add validation tests
- Update error handling
- Document validation rules
Phase 2: Handler Updates
- Update sharing handlers
- Add validation checks
- Implement error handling
- Add handler tests
Phase 3: Testing
- Add validation tests
- Test sharing scenarios
- Test error cases
- Test edge cases
Testing Strategy
Unit Tests
- Test parameter validation
- Test invalid combinations
- Test expiration handling
- Test access level validation
Integration Tests
- Test sharing updates
- Test permission checks
- Test error handling
- Test complete sharing flow
Success Criteria
- All sharing parameters are properly validated
- Invalid configurations are rejected
- Tests pass for all scenarios
- Documentation is updated
Rollout Plan
- Implement validation changes
- Update handlers
- Deploy to staging
- Monitor for issues
- Deploy to production
Appendix
Related Files
libs/handlers/src/sharing/validate.rs
libs/handlers/src/sharing/update_sharing.rs
libs/handlers/tests/sharing/sharing_params_test.rs
libs/models/src/sharing.rs
Sharing Parameter Reference
Valid parameter combinations:
- Public sharing must allow anonymous access
- Public sharing limited to read-only access
- Expiration date must be in the future
- Non-public sharing can have any access level