@@ -6,6 +6,14 @@ use ghactions::prelude::*;
66use ghactions_core:: repository:: reference:: RepositoryReference as Repository ;
77use ghastoolkit:: { CodeQL , codeql:: CodeQLLanguage } ;
88
9+ pub const BANNER : & str = r#" ___ _ ____ __ __ _ _ _
10+ / __\___ __| | ___ /___ \/ / /__\_ _| |_ /_\ ___| |_
11+ / / / _ \ / _` |/ _ \// / / / /_\ \ \/ / __|//_\\ / __| __|
12+ / /__| (_) | (_| | __/ \_/ / /___//__ > <| |_/ _ \ (__| |_
13+ \____/\___/ \__,_|\___\___,_\____/\__/ /_/\_\\__\_/ \_/\___|\__|"# ;
14+ pub const VERSION : & str = env ! ( "CARGO_PKG_VERSION" ) ;
15+ pub const AUTHORS : & str = env ! ( "CARGO_PKG_AUTHORS" ) ;
16+
917/// This action is for 3rd party CodeQL extractors to be used in GitHub Actions
1018#[ derive( Actions , Debug , Clone , Default ) ]
1119#[ action(
@@ -29,19 +37,29 @@ pub struct Action {
2937
3038 /// GitHub Repository where the extractor is located
3139 #[ input(
32- description = "GitHub Repository where the extractor is located" ,
40+ description = "GitHub Repository where the extractor(s) is located" ,
41+ split = "," ,
3342 required = true
3443 ) ]
35- extractor : String ,
44+ extractors : Vec < String > ,
3645
3746 /// Language(d) to use
3847 #[ input( description = "Language(s) to use" , split = "," , required = true ) ]
39- language : Vec < String > ,
48+ languages : Vec < String > ,
4049
4150 /// Queries packs to use
42- #[ input( description = "Query Packs to use" , split = "," ) ]
51+ #[ input( description = "Query Pack(s) to use" , split = "," ) ]
4352 packs : Vec < String > ,
4453
54+ /// Allow empty database. This allows for an extractor to error out if no database was
55+ /// created dur to no source code being found for that language.
56+ #[ input(
57+ description = "Allow empty database" ,
58+ default = false ,
59+ rename = "allow-empty-database"
60+ ) ]
61+ allow_empty_database : bool ,
62+
4563 /// CodeQL Version
4664 #[ input(
4765 description = "CodeQL Version" ,
@@ -62,6 +80,10 @@ pub struct Action {
6280 #[ input( description = "Attestation" , default = "false" ) ]
6381 attestation : bool ,
6482
83+ /// SARIF Results Directory
84+ #[ output( description = "SARIF Results Directory" , rename = "sarif-results" ) ]
85+ sarif_results : String ,
86+
6587 /// Version of the extractor to use
6688 #[ output( description = "Version of the extractor to use" ) ]
6789 version : String ,
@@ -78,31 +100,37 @@ impl Action {
78100 return std:: env:: current_dir ( ) . context ( "Failed to get current directory" ) ;
79101 }
80102 log:: debug!( "Using the provided working directory" ) ;
81- Ok ( std:: path:: PathBuf :: from ( & self . working_directory )
103+ std:: path:: PathBuf :: from ( & self . working_directory )
82104 . canonicalize ( )
83105 . context ( format ! (
84106 "Failed to get working directory `{}`" ,
85107 self . working_directory
86- ) ) ? )
108+ ) )
87109 }
88110
89111 /// Gets the repository to use for the extractor. If the repository is not provided,
90112 /// it will use the repository that the action is running in.
91- pub fn extractor_repository ( & self ) -> Result < Repository > {
92- let repo = if self . extractor . is_empty ( ) {
113+ pub fn extractor_repository ( & self ) -> Result < Vec < Repository > > {
114+ if self . extractors . is_empty ( ) {
93115 log:: debug!( "No extractor repository provided, using the current repository" ) ;
94- self . get_repository ( ) ?
95- } else {
96- log:: debug!( "Using the provided extractor repository" ) ;
97- self . extractor . clone ( )
98- } ;
99- log:: info!( "Extractor Repository :: {}" , repo) ;
100-
101- Ok ( Repository :: parse ( & repo) ?)
116+ return Ok ( vec ! [ Repository :: parse( & self . get_repository( ) ?) ?] ) ;
117+ }
118+
119+ log:: debug!( "Using the provided extractor repository" ) ;
120+
121+ Ok ( self
122+ . extractors
123+ . iter ( )
124+ . filter_map ( |ext| {
125+ Repository :: parse ( ext)
126+ . context ( format ! ( "Failed to parse extractor repository `{ext}`" ) )
127+ . ok ( )
128+ } )
129+ . collect :: < Vec < Repository > > ( ) )
102130 }
103131
104132 pub fn languages ( & self ) -> Vec < CodeQLLanguage > {
105- self . language
133+ self . languages
106134 . iter ( )
107135 . map ( |lang| CodeQLLanguage :: from ( lang. as_str ( ) ) )
108136 . collect ( )
@@ -111,10 +139,10 @@ impl Action {
111139 pub fn validate_languages ( & self , codeql_languages : & Vec < CodeQLLanguage > ) -> Result < ( ) > {
112140 for lang in self . languages ( ) {
113141 let mut supported = false ;
114- log:: debug!( "Validating language `{}`" , lang ) ;
142+ log:: debug!( "Validating language `{lang }`" ) ;
115143 for codeql_lang in codeql_languages {
116144 if lang. language ( ) . to_lowercase ( ) == codeql_lang. language ( ) . to_lowercase ( ) {
117- log:: debug!( "Language `{}` is supported" , lang ) ;
145+ log:: debug!( "Language `{lang }` is supported" ) ;
118146 supported = true ;
119147 break ;
120148 }
@@ -144,19 +172,23 @@ impl Action {
144172 pub async fn install_packs ( & self , codeql : & CodeQL ) -> Result < ( ) > {
145173 log:: info!( "Installing CodeQL Packs" ) ;
146174 for pack in & self . packs {
147- log:: info!( "Installing pack `{}`" , pack ) ;
175+ log:: info!( "Installing pack `{pack }`" ) ;
148176
149177 codeql
150178 . run ( vec ! [ "pack" , "download" , pack] )
151179 . await
152- . context ( format ! ( "Failed to download pack `{}`" , pack ) ) ?;
180+ . context ( format ! ( "Failed to download pack `{pack }`" ) ) ?;
153181 }
154182 Ok ( ( ) )
155183 }
156184
157185 pub fn attestation ( & self ) -> bool {
158186 self . attestation
159187 }
188+
189+ pub fn allow_empty_database ( & self ) -> bool {
190+ self . allow_empty_database
191+ }
160192}
161193
162194#[ cfg( test) ]
@@ -165,8 +197,8 @@ mod tests {
165197
166198 fn action ( ) -> Action {
167199 Action {
168- extractor : "owner/repo" . to_string ( ) ,
169- language : vec ! [ "iac" . to_string( ) ] ,
200+ extractors : vec ! [ "owner/repo" . to_string( ) ] ,
201+ languages : vec ! [ "iac" . to_string( ) ] ,
170202 ..Default :: default ( )
171203 }
172204 }
0 commit comments