Coverage for /usr/local/lib/python3.10/site-packages/opal_server-0.0.0-py3.10.egg/opal_server/policy/bundles/api.py: 48%

57 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 11:54 +0000

1import os 

2from pathlib import Path 

3from typing import List, Optional 

4 

5import fastapi.responses 

6from fastapi import APIRouter, Depends, Header, HTTPException, Query, Response, status 

7from git.repo import Repo 

8from opal_common.confi.confi import load_conf_if_none 

9from opal_common.git_utils.bundle_maker import BundleMaker 

10from opal_common.git_utils.commit_viewer import CommitViewer 

11from opal_common.git_utils.repo_cloner import RepoClonePathFinder 

12from opal_common.logger import logger 

13from opal_common.schemas.policy import PolicyBundle 

14from opal_server.config import opal_server_config 

15from starlette.responses import RedirectResponse 

16 

17router = APIRouter() 

18 

19 

20async def get_repo( 

21 base_clone_path: str = None, 

22 clone_subdirectory_prefix: str = None, 

23 use_fixed_path: bool = None, 

24) -> Repo: 

25 base_clone_path = load_conf_if_none( 

26 base_clone_path, opal_server_config.POLICY_REPO_CLONE_PATH 

27 ) 

28 clone_subdirectory_prefix = load_conf_if_none( 

29 clone_subdirectory_prefix, opal_server_config.POLICY_REPO_CLONE_FOLDER_PREFIX 

30 ) 

31 use_fixed_path = load_conf_if_none( 

32 use_fixed_path, opal_server_config.POLICY_REPO_REUSE_CLONE_PATH 

33 ) 

34 clone_path_finder = RepoClonePathFinder( 

35 base_clone_path=base_clone_path, 

36 clone_subdirectory_prefix=clone_subdirectory_prefix, 

37 use_fixed_path=use_fixed_path, 

38 ) 

39 repo_path = clone_path_finder.get_clone_path() 

40 

41 policy_repo_not_found_error = HTTPException( 

42 status_code=status.HTTP_503_SERVICE_UNAVAILABLE, 

43 detail="policy repo was not found", 

44 ) 

45 

46 if not repo_path: 

47 raise policy_repo_not_found_error 

48 

49 git_path = Path(os.path.join(repo_path, Path(".git"))) 

50 # TODO: at the moment opal server will 503 until it finishes cloning the policy repo 

51 # we might fix this in the future by signaling to the client that the repo is ready 

52 if not git_path.exists(): 52 ↛ 54line 52 didn't jump to line 54 because the condition on line 52 was always true

53 raise policy_repo_not_found_error 

54 return Repo(repo_path) 

55 

56 

57def normalize_path(path: str) -> Path: 

58 return Path(path[1:]) if path.startswith("/") else Path(path) 

59 

60 

61async def get_input_paths_or_throw( 

62 repo: Repo = Depends(get_repo), 

63 paths: Optional[List[str]] = Query(None, alias="path"), 

64) -> List[Path]: 

65 """Validates the :path query param, and return valid paths. 

66 

67 if an invalid path is provided, will throw 404. 

68 """ 

69 paths = paths or [] 

70 paths = [normalize_path(p) for p in paths] 

71 

72 # if the repo is currently being cloned - the repo.heads is empty 

73 if len(repo.heads) == 0: 

74 raise HTTPException( 

75 status_code=status.HTTP_503_SERVICE_UNAVAILABLE, 

76 detail="policy repo is not ready", 

77 ) 

78 

79 # verify all input paths exists under the commit hash 

80 with CommitViewer(repo.head.commit) as viewer: 

81 for path in paths: 

82 if not viewer.exists(path): 

83 raise HTTPException( 

84 status_code=status.HTTP_404_NOT_FOUND, 

85 detail=f"requested path {path} was not found in the policy repo!", 

86 ) 

87 

88 # the default of GET /policy (without path params) is to return all 

89 # the (opa) files in the repo. 

90 paths = paths or [Path(".")] 

91 return paths 

92 

93 

94@router.get("/policy", response_model=PolicyBundle) 

95async def get_policy( 

96 repo: Repo = Depends(get_repo), 

97 input_paths: List[Path] = Depends(get_input_paths_or_throw), 

98 base_hash: Optional[str] = Query( 

99 None, 

100 description="hash of previous bundle already downloaded, server will return a diff bundle.", 

101 ), 

102): 

103 maker = BundleMaker( 

104 repo, 

105 in_directories=set(input_paths), 

106 extensions=opal_server_config.FILTER_FILE_EXTENSIONS, 

107 root_manifest_path=opal_server_config.POLICY_REPO_MANIFEST_PATH, 

108 bundle_ignore=opal_server_config.BUNDLE_IGNORE, 

109 ) 

110 # check if commit exist in the repo 

111 revision = None 

112 if base_hash: 

113 try: 

114 revision = repo.rev_parse(base_hash) 

115 except ValueError: 

116 logger.warning(f"base_hash {base_hash} not exist in the repo") 

117 

118 if revision is None: 

119 return maker.make_bundle(repo.head.commit) 

120 try: 

121 old_commit = repo.commit(base_hash) 

122 return maker.make_diff_bundle(old_commit, repo.head.commit) 

123 except ValueError: 

124 raise HTTPException( 

125 status_code=status.HTTP_404_NOT_FOUND, 

126 detail=f"commit with hash {base_hash} was not found in the policy repo!", 

127 )