11import json
2+ import logging
23import os
4+ import subprocess
35from typing import Annotated
46
7+ import mjaf
58import requests
69from authlib .jose import jwt
710from authlib .jose .errors import BadSignatureError
1215from fastapi import HTTPException
1316
1417
15- load_dotenv ()
16-
17- SECRET_TOKEN = os .getenv ('SECRET_TOKEN' )
18-
19- # >>> GitHub
20- GITHUB_REPO = os .getenv ('GITHUB_REPO' )
21- GITHUB_TOKEN = os .getenv ('GITHUB_TOKEN' )
22- GITHUB_WORKFLOW = os .getenv ('GITHUB_WORKFLOW' )
23- # <<<
24-
25- # >>> GitLab
26- GITLAB_SERVER = os .getenv ('GITLAB_SERVER' )
27- GITLAB_TARGET_REPOSITORY_ID = os .getenv ('GITLAB_TARGET_REPOSITORY_ID' )
28- GITLAB_TOKEN = os .getenv ('GITLAB_TOKEN' )
29- # <<<
30-
31-
32- def get_expose_api_map ():
33- expose_api = {
34- 'gitlab' : False ,
35- 'github' : False ,
36- 'secret' : False ,
37- }
38-
39- if None not in (
40- GITLAB_SERVER ,
41- GITLAB_TARGET_REPOSITORY_ID ,
42- GITLAB_TOKEN ,
43- ):
44- expose_api ['gitlab' ] = True
18+ mjaf .logging .set_handlers (
19+ logger_name = __name__ ,
20+ level = logging .INFO ,
21+ )
22+ log = logging .getLogger (__name__ )
4523
46- if None not in (
47- GITHUB_REPO ,
48- GITHUB_TOKEN ,
49- GITHUB_WORKFLOW ,
50- ):
51- expose_api ['github' ] = True
5224
53- if SECRET_TOKEN is not None :
54- expose_api [ 'secret' ] = True
25+ load_dotenv ()
26+ log . info ( 'Environment loaded' )
5527
56- return expose_api
28+ SECRET_TOKEN = os . getenv ( 'SECRET_TOKEN' )
5729
5830
5931def get_jwt_keys (jwt_server_url ):
@@ -65,52 +37,33 @@ def get_jwt_keys(jwt_server_url):
6537 return jwks_keys
6638
6739
68- def request_gitlab_sync (image ):
69- request = requests .post (
70- url = (
71- f'{ GITLAB_SERVER } /api/v4/projects/'
72- f'{ GITLAB_TARGET_REPOSITORY_ID } /trigger/pipeline'
73- ),
74- data = {
75- 'token' : GITLAB_TOKEN ,
76- 'ref' : 'main' ,
77- 'variables[IMAGE]' : image ,
78- },
79- )
80-
81- if request .status_code != 200 :
82- raise HTTPException (
83- status_code = request .status_code ,
84- detail = f'Token server error: { request .text } ' ,
85- )
40+ def call_ducc (image : str | None , cvmfs_repository : str | None ):
41+ string = f'quack: { image } , { cvmfs_repository } '
8642
43+ log .info (f'{ image = } ' )
44+ log .info (f'{ cvmfs_repository = } ' )
8745
88- def request_github_sync (image ):
89- """
90- https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
91- """
92- request = requests .post (
93- url = (
94- f'https://api.github.com/repos/{ GITHUB_REPO } /actions/workflows/{ GITHUB_WORKFLOW } /dispatches' # noqa
95- ),
96- data = json .dumps ({
97- 'ref' : 'action-testing' ,
98- # 'inputs': {
99- # 'image': image,
100- # },
101- }),
102- headers = {
103- 'Accept' : 'application/vnd.github+json' ,
104- 'Authorization' : f'Bearer { GITHUB_TOKEN } ' ,
105- 'X-GitHub-Api-Version' : '2022-11-28' ,
106- },
46+ stdout = subprocess .run (
47+ [
48+ 'sudo' ,
49+ 'systemctl' ,
50+ 'stop' ,
51+ 'autofs' ,
52+ ],
10753 )
10854
109- if request .status_code != 200 :
110- raise HTTPException (
111- status_code = request .status_code ,
112- detail = f'Token server error: { request .text } ' ,
113- )
55+ # TODO: ensure cvmfs_ducc exists
56+ subprocess .run (
57+ [
58+ 'sudo' ,
59+ 'cvmfs_ducc' ,
60+ 'convert-single-image' ,
61+ image ,
62+ cvmfs_repository ,
63+ '--skip-podman' ,
64+ '--skip-thin-image' ,
65+ ],
66+ )
11467
11568
11669def check_authorization (
@@ -125,114 +78,89 @@ def check_authorization(
12578
12679app = FastAPI ()
12780
128- expose_api = get_expose_api_map ()
129-
130- gitlab_jwks_keys = None
131- if expose_api ['gitlab' ]:
132- gitlab_jwks_keys = get_jwt_keys (
133- f'{ GITLAB_SERVER } /oauth/discovery/keys' ,
134- )
135-
136-
137- github_jwks_keys = None
138- if expose_api ['github' ]:
139- github_jwks_keys = get_jwt_keys (
140- 'https://token.actions.githubusercontent.com/.well-known/jwks' ,
141- )
142-
14381
14482@app .get ('/' )
14583def root ():
14684 return {'message' : 'PSI Image Unpacker' }
14785
14886
149- if expose_api ['gitlab' ]:
150- @app .post ('/api/gitlab/sync/jwt' )
151- def gitlab_sync_jwt (
152- authorization : Annotated [str | None , Header ()] = None ,
153- image : str | None = None ,
154- ):
155-
156- check_authorization (authorization )
157- try :
158- claims = jwt .decode (
159- authorization ,
160- gitlab_jwks_keys ,
161- )
162- except DecodeError :
163- raise HTTPException (
164- status_code = 403 ,
165- detail = 'Invalid token: DecodeError' ,
166- )
167- except BadSignatureError :
168- raise HTTPException (
169- status_code = 403 ,
170- detail = 'Invalid token: BadSignatureError' ,
171- )
172- if claims ['iss' ] != GITLAB_SERVER :
173- raise HTTPException (
174- status_code = 403 ,
175- detail = f"Invalid issuer { claims ['iss' ]} " ,
176- )
177-
178- request_gitlab_sync (image )
179-
180-
181- if expose_api ['github' ]:
182- @app .post ('/api/github/sync/jwt' )
183- def github_sync_jwt (
184- authorization : Annotated [str | None , Header ()] = None ,
185- image : str | None = None ,
186- ):
87+ @app .post ('/api/gitlab/sync/jwt' )
88+ def gitlab_sync_jwt (
89+ authorization : Annotated [str | None , Header ()] = None ,
90+ image : str | None = None ,
91+ cvmfs_repository : str | None = None ,
92+ gitlab_server : str | None = None ,
93+ ):
94+ gitlab_jwks_keys = get_jwt_keys (
95+ f'https://{ gitlab_server } /oauth/discovery/keys' ,
96+ )
18797
188- check_authorization (authorization )
189- try :
190- claims = jwt .decode (
191- authorization ,
192- github_jwks_keys ,
193- )
194- except DecodeError :
195- raise HTTPException (
196- status_code = 403 ,
197- detail = 'Invalid token: DecodeError' ,
198- )
199- except BadSignatureError :
200- raise HTTPException (
201- status_code = 403 ,
202- detail = 'Invalid token: BadSignatureError' ,
203- )
204- if claims ['iss' ] != 'https://token.actions.githubusercontent.com' :
205- raise HTTPException (
206- status_code = 403 ,
207- detail = f"Invalid issuer { claims ['iss' ]} " ,
208- )
98+ check_authorization (authorization )
99+ try :
100+ claims = jwt .decode (
101+ authorization ,
102+ gitlab_jwks_keys ,
103+ )
104+ except DecodeError :
105+ raise HTTPException (
106+ status_code = 403 ,
107+ detail = 'Invalid token: DecodeError' ,
108+ )
109+ except BadSignatureError :
110+ raise HTTPException (
111+ status_code = 403 ,
112+ detail = 'Invalid token: BadSignatureError' ,
113+ )
114+ if claims ['iss' ] != gitlab_server :
115+ raise HTTPException (
209116
210- request_gitlab_sync (image )
117+ detail = f"Invalid issuer { claims ['iss' ]} " ,
118+ )
211119
120+ return call_ducc (image , cvmfs_repository )
212121
213- if expose_api ['secret' ] and expose_api ['gitlab' ]:
214- @app .post ('/api/gitlab/sync/secret' )
215- def gitlab_sync_secret (
216- authorization : Annotated [str | None , Header ()] = None ,
217- image : str | None = None ,
218- ):
219122
220- check_authorization (authorization )
123+ @app .post ('/api/github/sync/jwt' )
124+ def github_sync_jwt (
125+ authorization : Annotated [str | None , Header ()] = None ,
126+ image : str | None = None ,
127+ cvmfs_repository : str | None = None ,
128+ ):
129+ github_jwks_keys = get_jwt_keys (
130+ 'https://token.actions.githubusercontent.com/.well-known/jwks' ,
131+ )
221132
222- if authorization != SECRET_TOKEN :
223- raise HTTPException (
224- status_code = 401 ,
225- detail = 'Invalid authorization token' ,
226- )
133+ check_authorization (authorization )
134+ try :
135+ claims = jwt .decode (
136+ authorization ,
137+ github_jwks_keys ,
138+ )
139+ except DecodeError :
140+ raise HTTPException (
141+ status_code = 403 ,
142+ detail = 'Invalid token: DecodeError' ,
143+ )
144+ except BadSignatureError :
145+ raise HTTPException (
146+ status_code = 403 ,
147+ detail = 'Invalid token: BadSignatureError' ,
148+ )
149+ if claims ['iss' ] != 'https://token.actions.githubusercontent.com' :
150+ raise HTTPException (
151+ status_code = 403 ,
152+ detail = f"Invalid issuer { claims ['iss' ]} " ,
153+ )
227154
228- request_gitlab_sync (image )
155+ return call_ducc (image , cvmfs_repository )
229156
230157
231- if expose_api [ 'secret' ] and expose_api [ 'github' ] :
232- @app .post ('/api/github/ sync/secret' )
233- def github_sync_secret (
158+ if SECRET_TOKEN is not None :
159+ @app .post ('/api/sync/secret' )
160+ def gitlab_sync_secret (
234161 authorization : Annotated [str | None , Header ()] = None ,
235162 image : str | None = None ,
163+ cvmfs_repository : str | None = None ,
236164 ):
237165
238166 check_authorization (authorization )
@@ -243,4 +171,4 @@ def github_sync_secret(
243171 detail = 'Invalid authorization token' ,
244172 )
245173
246- request_github_sync (image )
174+ return call_ducc (image , cvmfs_repository )
0 commit comments