Skip to main content

brooks_lib/verifying/ps/
verify.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18//! Verification of CDNI Processing Stages JSON
19
20use serde::Serialize;
21
22use crate::verifying::ps::error::VerificationError;
23use crate::verifying::verify::{
24    AnalysisResult, CdniVerificationKey, MetadataAnalysisContext, MetadataVerificationError,
25    Verifier,
26};
27use crate::{
28    cdni::{
29        gmd::spec::TypedGenericMetadata,
30        ps::spec::{
31            ClientRequestStage, ClientResponseStage, ExpressionMatch, Header, HeaderTransform,
32            MatchGroup, OriginRequestStage, OriginResponseStage, ProcessingStages,
33            RequestTransform, ResponseTransform, StageMetadata, StageRules, SyntheticResponse,
34            TypedClientRequestStage, TypedClientResponseStage, TypedExpressionMatch,
35            TypedGenericStage, TypedHeader, TypedHeaderTransform, TypedMatchGroup,
36            TypedOriginRequestStage, TypedOriginResponseStage, TypedProcessingStages,
37            TypedRequestTransform, TypedResponseTransform, TypedStage, TypedStageMetadata,
38            TypedStageRules, TypedSyntheticResponse,
39        },
40    },
41    environment::scope::Scopes,
42    mel::{
43        analysis::{Analyzed, analyze},
44        ast::Expr,
45        compiler,
46        types::Type,
47    },
48    visitors::PsVisitor,
49};
50
51use std::fmt::Debug;
52
53type PsVisitorResult<T, E> = Result<T, E>;
54
55#[derive(Debug, Clone, Default)]
56pub enum PsVerificationKey {
57    Expr(Expr<Analyzed>),
58    ExprPair(Option<Expr<Analyzed>>, Option<Expr<Analyzed>>),
59    #[default]
60    None,
61}
62
63impl Serialize for PsVerificationKey {
64    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65    where
66        S: serde::Serializer,
67    {
68        serializer.serialize_none()
69    }
70}
71
72impl TypedGenericStage {
73    pub fn typed(&self) -> Result<TypedStage<()>, Box<VerificationError>> {
74        if self.tpe == TypedClientRequestStage::<()>::typed_cdni_metadata_name() {
75            let stages = serde_json::from_str::<TypedClientRequestStage<()>>(
76                &(serde_json::to_string(self).map_err(|_| VerificationError::ParseError)?),
77            )
78            .map_err(|_| VerificationError::ParseError)?;
79            Ok(TypedStage::ClientRequest(stages))
80        } else if self.tpe == TypedClientResponseStage::<()>::typed_cdni_metadata_name() {
81            let stages = serde_json::from_str::<TypedClientResponseStage<()>>(
82                &(serde_json::to_string(self).map_err(|_| VerificationError::ParseError)?),
83            )
84            .map_err(|_| VerificationError::ParseError)?;
85            Ok(TypedStage::ClientResponse(stages))
86        } else if self.tpe == TypedOriginRequestStage::<()>::typed_cdni_metadata_name() {
87            let stages = serde_json::from_str::<TypedOriginRequestStage<()>>(
88                &(serde_json::to_string(self).map_err(|_| VerificationError::ParseError)?),
89            )
90            .map_err(|_| VerificationError::ParseError)?;
91            Ok(TypedStage::OriginRequest(stages))
92        } else if self.tpe == TypedOriginResponseStage::<()>::typed_cdni_metadata_name() {
93            let stages = serde_json::from_str::<TypedOriginResponseStage<()>>(
94                &(serde_json::to_string(self).map_err(|_| VerificationError::ParseError)?),
95            )
96            .map_err(|_| VerificationError::ParseError)?;
97            Ok(TypedStage::OriginResponse(stages))
98        } else {
99            Err(VerificationError::InvalidTypedResponseStage.into())
100        }
101    }
102}
103
104#[derive(Debug, Clone, Default)]
105pub(crate) struct PsVerifier {}
106
107impl PsVerifier {
108    pub fn compile_and_analyze_expr(
109        source: &str,
110        scopes: &Scopes<Type>,
111    ) -> Result<Expr<Analyzed>, Box<VerificationError>> {
112        let expr = compiler::compile(source)
113            .map_err(|e| Box::new(VerificationError::ExpressionCompile(Box::new(e))))?;
114        analyze(&expr, scopes).map_err(|e| Box::new(VerificationError::ExpressionAnalyze(e)))
115    }
116}
117
118#[allow(clippy::large_enum_variant)]
119#[derive(Debug, Clone)]
120pub(crate) enum PsVerifierContextValue {
121    ProcessingStages(TypedProcessingStages<PsVerificationKey>),
122    StageRules(TypedStageRules<PsVerificationKey>),
123    ExpressionMatch(TypedExpressionMatch<PsVerificationKey>),
124    StageMetadata(TypedStageMetadata<PsVerificationKey>),
125    GenericMetadata(TypedGenericMetadata<PsVerificationKey>),
126    RequestTransform(TypedRequestTransform<PsVerificationKey>),
127    ResponseTransform(TypedResponseTransform<PsVerificationKey>),
128    HeaderTransform(TypedHeaderTransform<PsVerificationKey>),
129    Header(TypedHeader<PsVerificationKey>),
130    SyntheticResponse(TypedSyntheticResponse<PsVerificationKey>),
131    MatchGroup(TypedMatchGroup<PsVerificationKey>),
132    ClientRequestStage(TypedClientRequestStage<PsVerificationKey>),
133    ClientResponseStage(TypedClientResponseStage<PsVerificationKey>),
134    OriginRequestStage(TypedOriginRequestStage<PsVerificationKey>),
135    OriginResponseStage(TypedOriginResponseStage<PsVerificationKey>),
136}
137
138#[derive(Debug, Default)]
139pub(crate) struct PsVerifierContext {
140    pub value: Option<PsVerifierContextValue>,
141    pub scopes: Scopes<Type>,
142}
143
144type VerifiedPs = ProcessingStages<PsVerificationKey>;
145
146macro_rules! expect_maybe_some_value {
147    ($name:expr, $value:path) => {
148        match &$name {
149            Some($value(v)) => Some(v),
150            None => None,
151            _ => return Err(Box::new(VerificationError::WrongType)),
152        }
153    };
154}
155
156macro_rules! expect_some_value {
157    ($name:expr, $value:path) => {
158        match &$name {
159            Some($value(v)) => v,
160            None => return Err(Box::new(VerificationError::NoVerifiedValue)),
161            _ => return Err(Box::new(VerificationError::WrongType)),
162        }
163    };
164}
165
166macro_rules! make_context_value {
167    ($value:expr, $vt:path, $a:ident, $tvt:ident) => {
168        Some($vt($tvt::<$a>::typed_value($value)))
169    };
170}
171
172macro_rules! check_generic_md_typename {
173    ($value:expr, $tn:ident) => {
174        if $value.tpe != $tn::<()>::typed_cdni_metadata_name() {
175            return Err(Box::new(VerificationError::WrongGenericMetadataTypeName(
176                $tn::<()>::typed_cdni_metadata_name(),
177                $value.tpe.clone(),
178            )));
179        }
180    };
181}
182
183#[derive(Debug)]
184pub struct PsMetadataAnalyzer {}
185
186impl Verifier<MetadataAnalysisContext, MetadataVerificationError> for PsMetadataAnalyzer {
187    fn analyze(
188        &self,
189        v: &TypedGenericMetadata<()>,
190        input: MetadataAnalysisContext,
191    ) -> AnalysisResult<MetadataAnalysisContext, MetadataVerificationError> {
192        let generic_stage = serde_json::from_value::<TypedGenericStage>(
193            serde_json::to_value(v)
194                .map_err(|e| MetadataVerificationError::JsonError(e.to_string()))?,
195        )
196        .map_err(|e| MetadataVerificationError::JsonError(e.to_string()))?;
197
198        // TODO: It may be possible to optimize how the analyzed metadata is interpreted
199        // if the if-rule in the MatchGroup is a constant.
200        let res = verify_ps_request_stage(&generic_stage, &input.scopes)
201            .map_err(MetadataVerificationError::PsVerificationError)?;
202
203        Ok((input, CdniVerificationKey::Stage(Box::new(res))))
204    }
205
206    fn type_name(&self, candidate: &str) -> bool {
207        candidate == TypedClientRequestStage::<()>::typed_cdni_metadata_name()
208            || candidate == TypedClientResponseStage::<()>::typed_cdni_metadata_name()
209            || candidate == TypedOriginRequestStage::<()>::typed_cdni_metadata_name()
210            || candidate == TypedOriginResponseStage::<()>::typed_cdni_metadata_name()
211    }
212}
213
214impl PsVisitor<(), PsVerifierContext, PsVerifierContext, Box<VerificationError>> for PsVerifier {
215    fn visit_processing_stages(
216        &mut self,
217        v: &TypedProcessingStages<()>,
218        c: PsVerifierContext,
219    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
220        check_generic_md_typename!(v, TypedProcessingStages);
221
222        let mut result = ProcessingStages::<PsVerificationKey>::default();
223        let mut rc = c;
224
225        let v = &v.value;
226
227        for csr in &v.client_req {
228            rc = self.visit_stage_rules(csr, rc)?;
229            if let Some(tsr) =
230                expect_maybe_some_value!(rc.value, PsVerifierContextValue::StageRules)
231            {
232                result.client_req.push(tsr.clone());
233            };
234        }
235
236        for csr in &v.client_res {
237            rc = self.visit_stage_rules(csr, rc)?;
238            if let Some(tsr) =
239                expect_maybe_some_value!(rc.value, PsVerifierContextValue::StageRules)
240            {
241                result.client_res.push(tsr.clone());
242            };
243        }
244
245        for csr in &v.origin_req {
246            rc = self.visit_stage_rules(csr, rc)?;
247            if let Some(tsr) =
248                expect_maybe_some_value!(rc.value, PsVerifierContextValue::StageRules)
249            {
250                result.origin_req.push(tsr.clone());
251            };
252        }
253
254        for csr in &v.origin_res {
255            rc = self.visit_stage_rules(csr, rc)?;
256            if let Some(tsr) =
257                expect_maybe_some_value!(rc.value, PsVerifierContextValue::StageRules)
258            {
259                result.origin_res.push(tsr.clone());
260            };
261        }
262
263        rc.value = make_context_value!(
264            result,
265            PsVerifierContextValue::ProcessingStages,
266            PsVerificationKey,
267            TypedProcessingStages
268        );
269
270        Ok(rc)
271    }
272
273    fn visit_stage_rules(
274        &mut self,
275        v: &TypedStageRules<()>,
276        mut c: PsVerifierContext,
277    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
278        // Check whether the expression has the right type!
279
280        check_generic_md_typename!(v, TypedStageRules);
281
282        let v = &v.value;
283
284        let mut result = if let Some(mtch) = &v.mtch {
285            c = self.visit_expression_match(mtch, c)?;
286
287            let expr = expect_maybe_some_value!(&c.value, PsVerifierContextValue::ExpressionMatch);
288
289            StageRules::<PsVerificationKey> {
290                mtch: expr.cloned(),
291                stage_metadata: TypedStageMetadata::default(),
292                aug: PsVerificationKey::None,
293            }
294        } else {
295            StageRules::<PsVerificationKey> {
296                mtch: None,
297                stage_metadata: TypedStageMetadata::default(),
298                aug: PsVerificationKey::None,
299            }
300        };
301
302        c = self.visit_stage_metadata(&v.stage_metadata, c)?;
303
304        result.stage_metadata =
305            expect_some_value!(&c.value, PsVerifierContextValue::StageMetadata).clone();
306
307        Ok(PsVerifierContext {
308            scopes: c.scopes.clone(),
309            value: make_context_value!(
310                result,
311                PsVerifierContextValue::StageRules,
312                PsVerificationKey,
313                TypedStageRules
314            ),
315        })
316    }
317
318    fn visit_expression_match(
319        &mut self,
320        v: &TypedExpressionMatch<()>,
321        c: PsVerifierContext,
322    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
323        check_generic_md_typename!(v, TypedExpressionMatch);
324
325        let v = &v.value;
326
327        let expr = Self::compile_and_analyze_expr(&v.expression, &c.scopes)?;
328
329        if expr.tipe() != Type::Boolean {
330            return Err(Box::new(VerificationError::ExpressionWrongType(
331                Type::Boolean,
332                expr.tipe(),
333            )));
334        }
335        Ok(PsVerifierContext {
336            scopes: c.scopes.clone(),
337            value: make_context_value!(
338                ExpressionMatch {
339                    expression: v.expression.clone(),
340                    aug: PsVerificationKey::Expr(expr),
341                },
342                PsVerifierContextValue::ExpressionMatch,
343                PsVerificationKey,
344                TypedExpressionMatch
345            ),
346        })
347    }
348
349    fn visit_stage_metadata(
350        &mut self,
351        v: &TypedStageMetadata<()>,
352        mut c: PsVerifierContext,
353    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
354        check_generic_md_typename!(v, TypedStageMetadata);
355
356        let v = &v.value;
357
358        let mut result = if let Some(generic) = &v.generic {
359            let mut result: Vec<TypedGenericMetadata<PsVerificationKey>> = vec![];
360            for generics in generic {
361                c = self.visit_generic_metadata(generics, c)?;
362                let generic =
363                    expect_some_value!(&c.value, PsVerifierContextValue::GenericMetadata).clone();
364                result.push(generic);
365            }
366
367            StageMetadata {
368                request_xform: None,
369                response_xform: None,
370                generic: Some(result),
371                aug: PsVerificationKey::None,
372            }
373        } else {
374            StageMetadata {
375                request_xform: None,
376                response_xform: None,
377                generic: None,
378                aug: PsVerificationKey::None,
379            }
380        };
381
382        result.request_xform = if let Some(reqt) = &v.request_xform {
383            c = self.visit_request_transform(reqt, c)?;
384            Some(expect_some_value!(&c.value, PsVerifierContextValue::RequestTransform).clone())
385        } else {
386            None
387        };
388
389        result.response_xform = if let Some(reqt) = &v.response_xform {
390            c = self.visit_response_transform(reqt, c)?;
391            Some(expect_some_value!(&c.value, PsVerifierContextValue::ResponseTransform).clone())
392        } else {
393            None
394        };
395
396        Ok(PsVerifierContext {
397            scopes: c.scopes.clone(),
398            value: make_context_value!(
399                result,
400                PsVerifierContextValue::StageMetadata,
401                PsVerificationKey,
402                TypedStageMetadata
403            ),
404        })
405    }
406
407    fn visit_request_transform(
408        &mut self,
409        v: &TypedRequestTransform<()>,
410        mut c: PsVerifierContext,
411    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
412        check_generic_md_typename!(v, TypedRequestTransform);
413
414        let v = &v.value;
415
416        let mut result = if let Some(header_xform) = &v.xform {
417            c = self.visit_header_transform(header_xform, c)?;
418            let header =
419                Some(expect_some_value!(&c.value, PsVerifierContextValue::HeaderTransform).clone());
420
421            RequestTransform {
422                xform: header,
423                uri: v.uri.clone(),
424                uri_is_expr: v.uri_is_expr,
425                aug: PsVerificationKey::None,
426            }
427        } else {
428            RequestTransform {
429                xform: None,
430                uri: v.uri.clone(),
431                uri_is_expr: v.uri_is_expr,
432                aug: PsVerificationKey::None,
433            }
434        };
435
436        result.aug = if let Some(uri) = &v.uri {
437            if let Some(uri_is_expr) = &v.uri_is_expr
438                && *uri_is_expr
439            {
440                let expr = Self::compile_and_analyze_expr(uri, &c.scopes)?;
441
442                if expr.tipe() != Type::String {
443                    return Err(Box::new(VerificationError::ExpressionWrongType(
444                        Type::String,
445                        expr.tipe(),
446                    )));
447                }
448                PsVerificationKey::Expr(expr)
449            } else {
450                PsVerificationKey::None
451            }
452        } else {
453            PsVerificationKey::None
454        };
455
456        Ok(PsVerifierContext {
457            scopes: c.scopes.clone(),
458            value: make_context_value!(
459                result,
460                PsVerifierContextValue::RequestTransform,
461                PsVerificationKey,
462                TypedRequestTransform
463            ),
464        })
465    }
466
467    fn visit_response_transform(
468        &mut self,
469        v: &TypedResponseTransform<()>,
470        mut c: PsVerifierContext,
471    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
472        check_generic_md_typename!(v, TypedResponseTransform);
473
474        let v = &v.value;
475
476        let mut result = if let Some(header_xform) = &v.xform {
477            c = self.visit_header_transform(header_xform, c)?;
478            let header =
479                Some(expect_some_value!(&c.value, PsVerifierContextValue::HeaderTransform).clone());
480
481            ResponseTransform {
482                xform: header,
483                response_status: v.response_status.clone(),
484                response_status_expr: v.response_status_expr,
485                synthetic: None,
486                aug: PsVerificationKey::None,
487            }
488        } else {
489            ResponseTransform {
490                xform: None,
491                response_status: v.response_status.clone(),
492                response_status_expr: v.response_status_expr,
493                synthetic: None,
494                aug: PsVerificationKey::None,
495            }
496        };
497
498        result.synthetic = if let Some(synthetic) = &v.synthetic {
499            c = self.visit_synthetic_response(synthetic, c)?;
500            Some(expect_some_value!(&c.value, PsVerifierContextValue::SyntheticResponse).clone())
501        } else {
502            None
503        };
504
505        result.aug = if let Some(rs) = &v.response_status {
506            if let Some(rs_is_expr) = &v.response_status_expr
507                && *rs_is_expr
508            {
509                let expr = Self::compile_and_analyze_expr(rs, &c.scopes)?;
510
511                if expr.tipe() != Type::Integer {
512                    return Err(Box::new(VerificationError::ExpressionWrongType(
513                        Type::Integer,
514                        expr.tipe(),
515                    )));
516                }
517                PsVerificationKey::Expr(expr)
518            } else {
519                PsVerificationKey::None
520            }
521        } else {
522            PsVerificationKey::None
523        };
524
525        Ok(PsVerifierContext {
526            scopes: c.scopes.clone(),
527            value: make_context_value!(
528                result,
529                PsVerifierContextValue::ResponseTransform,
530                PsVerificationKey,
531                TypedResponseTransform
532            ),
533        })
534    }
535
536    fn visit_generic_metadata(
537        &mut self,
538        v: &TypedGenericMetadata<()>,
539        c: PsVerifierContext,
540    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
541        // We only verify that the type starts with "MI.".
542        if !v.tpe.starts_with("MI.") {
543            return Err(Box::new(VerificationError::WrongGenericMetadataTypeName(
544                "MI. ...".to_string(),
545                v.tpe.clone(),
546            )));
547        }
548
549        Ok(PsVerifierContext {
550            scopes: c.scopes.clone(),
551            value: make_context_value!(
552                TypedGenericMetadata {
553                    tpe: v.tpe.clone(),
554                    value: v.value.clone(),
555                    aug: PsVerificationKey::None
556                },
557                PsVerifierContextValue::GenericMetadata,
558                PsVerificationKey,
559                TypedGenericMetadata
560            ),
561        })
562    }
563
564    fn visit_header_transform(
565        &mut self,
566        v: &TypedHeaderTransform<()>,
567        mut c: PsVerifierContext,
568    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
569        check_generic_md_typename!(v, TypedHeaderTransform);
570        let v = &v.value;
571
572        let mut result = HeaderTransform {
573            delete: v.delete.clone(),
574            ..Default::default()
575        };
576
577        result.add = if let Some(adds) = &v.add {
578            let mut verified_adds: Vec<TypedHeader<PsVerificationKey>> = vec![];
579            for add in adds {
580                c = self.visit_header(add, c)?;
581                verified_adds
582                    .push(expect_some_value!(&c.value, PsVerifierContextValue::Header).clone());
583            }
584            Some(verified_adds)
585        } else {
586            None
587        };
588
589        result.replace = if let Some(replaceds) = &v.replace {
590            let mut verified_replaceds: Vec<TypedHeader<PsVerificationKey>> = vec![];
591            for replaced in replaceds {
592                c = self.visit_header(replaced, c)?;
593                verified_replaceds
594                    .push(expect_some_value!(&c.value, PsVerifierContextValue::Header).clone());
595            }
596            Some(verified_replaceds)
597        } else {
598            None
599        };
600        Ok(PsVerifierContext {
601            scopes: c.scopes.clone(),
602            value: make_context_value!(
603                result,
604                PsVerifierContextValue::HeaderTransform,
605                PsVerificationKey,
606                TypedHeaderTransform
607            ),
608        })
609    }
610
611    fn visit_header(
612        &mut self,
613        v: &TypedHeader<()>,
614        c: PsVerifierContext,
615    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
616        check_generic_md_typename!(v, TypedHeader);
617
618        let v = &v.value;
619        let mut result = Header::<PsVerificationKey> {
620            name: v.name.clone(),
621            value: v.value.clone(),
622            value_expr: v.value_expr,
623            aug: PsVerificationKey::None,
624        };
625
626        result.aug = if let Some(hv_is_expr) = &v.value_expr
627            && *hv_is_expr
628        {
629            let expr = Self::compile_and_analyze_expr(&v.value, &c.scopes)?;
630
631            if expr.tipe() != Type::String {
632                return Err(Box::new(VerificationError::ExpressionWrongType(
633                    Type::String,
634                    expr.tipe(),
635                )));
636            }
637            PsVerificationKey::Expr(expr)
638        } else {
639            PsVerificationKey::None
640        };
641
642        Ok(PsVerifierContext {
643            scopes: c.scopes.clone(),
644            value: make_context_value!(
645                result,
646                PsVerifierContextValue::Header,
647                PsVerificationKey,
648                TypedHeader
649            ),
650        })
651    }
652
653    fn visit_synthetic_response(
654        &mut self,
655        v: &TypedSyntheticResponse<()>,
656        mut c: PsVerifierContext,
657    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
658        check_generic_md_typename!(v, TypedSyntheticResponse);
659        let v = &v.value;
660
661        let mut result = SyntheticResponse {
662            headers: None,
663            response_status: v.response_status.clone(),
664            response_status_expr: v.response_status_expr,
665            body: v.body.clone(),
666            body_expr: v.body_expr,
667            aug: PsVerificationKey::None,
668        };
669
670        result.headers = if let Some(headers) = &v.headers {
671            let mut verified_headers: Vec<TypedHeader<PsVerificationKey>> = vec![];
672            for header in headers {
673                c = self.visit_header(header, c)?;
674                verified_headers
675                    .push(expect_some_value!(&c.value, PsVerifierContextValue::Header).clone());
676            }
677            Some(verified_headers)
678        } else {
679            None
680        };
681
682        let response_status_expr = if let Some(rs) = &v.response_status {
683            if let Some(rs_is_expr) = &v.response_status_expr
684                && *rs_is_expr
685            {
686                let expr = Self::compile_and_analyze_expr(rs, &c.scopes)?;
687
688                if expr.tipe() != Type::Integer {
689                    return Err(Box::new(VerificationError::ExpressionWrongType(
690                        Type::Integer,
691                        expr.tipe(),
692                    )));
693                }
694                Some(expr)
695            } else {
696                None
697            }
698        } else {
699            None
700        };
701
702        let body_expr = if let Some(body) = &v.body {
703            if let Some(body_is_expr) = &v.body_expr
704                && *body_is_expr
705            {
706                let expr = Self::compile_and_analyze_expr(body, &c.scopes)?;
707
708                if expr.tipe() != Type::String {
709                    return Err(Box::new(VerificationError::ExpressionWrongType(
710                        Type::String,
711                        expr.tipe(),
712                    )));
713                }
714                Some(expr)
715            } else {
716                None
717            }
718        } else {
719            None
720        };
721
722        result.aug = PsVerificationKey::ExprPair(response_status_expr, body_expr);
723
724        Ok(PsVerifierContext {
725            scopes: c.scopes.clone(),
726            value: make_context_value!(
727                result,
728                PsVerifierContextValue::SyntheticResponse,
729                PsVerificationKey,
730                TypedSyntheticResponse
731            ),
732        })
733    }
734
735    fn visit_client_request_stage(
736        &mut self,
737        v: &TypedClientRequestStage<()>,
738        mut c: PsVerifierContext,
739    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
740        check_generic_md_typename!(v, TypedClientRequestStage);
741        let v = &v.value;
742
743        // Verify each of the match groups!
744        let mut verified_mgs: Vec<TypedMatchGroup<PsVerificationKey>> = vec![];
745        for mg in &v.match_groups {
746            c = self.visit_match_group(mg, c)?;
747            verified_mgs
748                .push(expect_some_value!(&c.value, PsVerifierContextValue::MatchGroup).clone());
749        }
750
751        let result = ClientRequestStage {
752            match_groups: verified_mgs,
753            aug: PsVerificationKey::None,
754        };
755
756        Ok(PsVerifierContext {
757            scopes: c.scopes.clone(),
758            value: make_context_value!(
759                result,
760                PsVerifierContextValue::ClientRequestStage,
761                PsVerificationKey,
762                TypedClientRequestStage
763            ),
764        })
765    }
766
767    fn visit_match_group(
768        &mut self,
769        v: &TypedMatchGroup<()>,
770        mut c: PsVerifierContext,
771    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
772        check_generic_md_typename!(v, TypedMatchGroup);
773        let v = &v.value;
774
775        c = self.visit_stage_rules(&v.if_rule, c)?;
776        let verified_if_rule =
777            expect_some_value!(&c.value, PsVerifierContextValue::StageRules).clone();
778
779        let result = if let Some(else_if_rules) = &v.else_ifs {
780            // Verify each of the match groups!
781            let mut verified_eirs: Vec<TypedStageRules<PsVerificationKey>> = vec![];
782            for eir in else_if_rules {
783                c = self.visit_stage_rules(eir, c)?;
784                verified_eirs
785                    .push(expect_some_value!(&c.value, PsVerifierContextValue::StageRules).clone());
786            }
787            MatchGroup {
788                if_rule: verified_if_rule,
789                else_ifs: Some(verified_eirs),
790                aug: PsVerificationKey::None,
791            }
792        } else {
793            MatchGroup {
794                if_rule: verified_if_rule,
795                else_ifs: None,
796                aug: PsVerificationKey::None,
797            }
798        };
799        Ok(PsVerifierContext {
800            scopes: c.scopes.clone(),
801            value: make_context_value!(
802                result,
803                PsVerifierContextValue::MatchGroup,
804                PsVerificationKey,
805                TypedMatchGroup
806            ),
807        })
808    }
809
810    fn visit_origin_request_stage(
811        &mut self,
812        v: &TypedOriginRequestStage<()>,
813        mut c: PsVerifierContext,
814    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
815        check_generic_md_typename!(v, TypedOriginRequestStage);
816        let v = &v.value;
817
818        // Verify each of the match groups!
819        let mut verified_mgs: Vec<TypedMatchGroup<PsVerificationKey>> = vec![];
820        for mg in &v.match_groups {
821            c = self.visit_match_group(mg, c)?;
822            verified_mgs
823                .push(expect_some_value!(&c.value, PsVerifierContextValue::MatchGroup).clone());
824        }
825
826        let result = OriginRequestStage {
827            match_groups: verified_mgs,
828            aug: PsVerificationKey::None,
829        };
830
831        Ok(PsVerifierContext {
832            scopes: c.scopes.clone(),
833            value: make_context_value!(
834                result,
835                PsVerifierContextValue::OriginRequestStage,
836                PsVerificationKey,
837                TypedOriginRequestStage
838            ),
839        })
840    }
841
842    fn visit_client_response_stage(
843        &mut self,
844        v: &TypedClientResponseStage<()>,
845        mut c: PsVerifierContext,
846    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
847        check_generic_md_typename!(v, TypedClientResponseStage);
848        let v = &v.value;
849
850        // Verify each of the match groups!
851        let mut verified_mgs: Vec<TypedMatchGroup<PsVerificationKey>> = vec![];
852        for mg in &v.match_groups {
853            c = self.visit_match_group(mg, c)?;
854            verified_mgs
855                .push(expect_some_value!(&c.value, PsVerifierContextValue::MatchGroup).clone());
856        }
857
858        let result = ClientResponseStage {
859            match_groups: verified_mgs,
860            aug: PsVerificationKey::None,
861        };
862
863        Ok(PsVerifierContext {
864            scopes: c.scopes.clone(),
865            value: make_context_value!(
866                result,
867                PsVerifierContextValue::ClientResponseStage,
868                PsVerificationKey,
869                TypedClientResponseStage
870            ),
871        })
872    }
873
874    fn visit_origin_response_stage(
875        &mut self,
876        v: &TypedOriginResponseStage<()>,
877        mut c: PsVerifierContext,
878    ) -> PsVisitorResult<PsVerifierContext, Box<VerificationError>> {
879        check_generic_md_typename!(v, TypedOriginResponseStage);
880        let v = &v.value;
881
882        // Verify each of the match groups!
883        let mut verified_mgs: Vec<TypedMatchGroup<PsVerificationKey>> = vec![];
884        for mg in &v.match_groups {
885            c = self.visit_match_group(mg, c)?;
886            verified_mgs
887                .push(expect_some_value!(&c.value, PsVerifierContextValue::MatchGroup).clone());
888        }
889
890        let result = OriginResponseStage {
891            match_groups: verified_mgs,
892            aug: PsVerificationKey::None,
893        };
894
895        Ok(PsVerifierContext {
896            scopes: c.scopes.clone(),
897            value: make_context_value!(
898                result,
899                PsVerifierContextValue::OriginResponseStage,
900                PsVerificationKey,
901                TypedOriginResponseStage
902            ),
903        })
904    }
905}
906
907pub(crate) fn verifier() -> (PsVerifier, PsVerifierContext) {
908    (PsVerifier {}, PsVerifierContext::default())
909}
910
911/// Verify the (semantic) validity of some CDNI Processing Stages JSON
912///
913/// In particular, test whether
914/// 1. the MEL expressions have the proper types, and
915/// 2. the generic metadata type names are correct.
916///
917pub fn verify_ps(
918    stages: &TypedProcessingStages<()>,
919) -> Result<TypedProcessingStages<PsVerificationKey>, Box<VerificationError>> {
920    let (mut verifier, context) = verifier();
921    let value = &stages;
922    let result = verifier.visit_processing_stages(value, context)?;
923    Ok(expect_some_value!(&result.value, PsVerifierContextValue::ProcessingStages).clone())
924}
925
926/// Verify the (semantic) validity of some CDNI Processing Stages Request Stage JSON
927///
928pub fn verify_ps_request_stage(
929    stage: &TypedGenericStage,
930    scopes: &Scopes<Type>,
931) -> Result<TypedStage<PsVerificationKey>, Box<VerificationError>> {
932    match stage.typed()? {
933        TypedStage::ClientRequest(crq) => {
934            let (mut verifier, mut context) = verifier();
935            context.scopes = scopes.clone();
936            let result = verifier.visit_client_request_stage(&crq, context)?;
937            Ok(TypedStage::ClientRequest(
938                expect_some_value!(&result.value, PsVerifierContextValue::ClientRequestStage)
939                    .clone(),
940            ))
941        }
942        TypedStage::ClientResponse(crs) => {
943            let (mut verifier, mut context) = verifier();
944            context.scopes = scopes.clone();
945            let result = verifier.visit_client_response_stage(&crs, context)?;
946            Ok(TypedStage::ClientResponse(
947                expect_some_value!(&result.value, PsVerifierContextValue::ClientResponseStage)
948                    .clone(),
949            ))
950        }
951        TypedStage::OriginRequest(orq) => {
952            let (mut verifier, mut context) = verifier();
953            context.scopes = scopes.clone();
954            let result = verifier.visit_origin_request_stage(&orq, context)?;
955            Ok(TypedStage::OriginRequest(
956                expect_some_value!(&result.value, PsVerifierContextValue::OriginRequestStage)
957                    .clone(),
958            ))
959        }
960        TypedStage::OriginResponse(ors) => {
961            let (mut verifier, mut context) = verifier();
962            context.scopes = scopes.clone();
963            let result = verifier.visit_origin_response_stage(&ors, context)?;
964            Ok(TypedStage::OriginResponse(
965                expect_some_value!(&result.value, PsVerifierContextValue::OriginResponseStage)
966                    .clone(),
967            ))
968        }
969    }
970}
971
972#[cfg(test)]
973mod test_verify {
974    use std::assert_matches;
975
976    use crate::cdni::ps::spec::{
977        HeaderTransform, ResponseTransform, SyntheticResponse, TypedHeaderTransform,
978        TypedSyntheticResponse,
979    };
980    use crate::mel::types::Type;
981    use crate::verifying::ps::verify::{
982        PsVerificationKey, PsVerifierContextValue, VerificationError, verifier, verify_ps,
983    };
984    use crate::visitors::PsVisitor;
985    use crate::{cdni::ps::spec::TypedResponseTransform, mel::ast::Expr::BinaryExpr};
986
987    use crate::cdni::tests::test_helpers::{
988        expression_match, generic_metadata, header_transform, processing_stages, request_transform,
989        response_transform, synthetic_response, typed_header,
990    };
991
992    #[test]
993    fn test_verify_bad_generic_md_typename() {
994        let mut stages = processing_stages(vec![], vec![], vec![], vec![]);
995        stages.tpe = "MI.ProcessigStages".to_string();
996
997        let result = verify_ps(&stages)
998            .expect_err("Could verify CDNI generic metadata with invalid metadata type name");
999
1000        assert_matches!(*result, VerificationError::WrongGenericMetadataTypeName(expected, actual) if expected == "MI.ProcessingStages" && actual == "MI.ProcessigStages")
1001    }
1002
1003    #[test]
1004    fn test_verify_generic_metadata_with_bad_type_name() {
1005        let generic = generic_metadata("Mi.CachePolicy", None);
1006
1007        let (mut verifier, context) = verifier();
1008        let result = verifier
1009            .visit_generic_metadata(&generic, context)
1010            .expect_err("Could verify CDNI generic metadata with invalid metadata type name");
1011
1012        assert_matches!(*result, VerificationError::WrongGenericMetadataTypeName(expected, actual) if expected == "MI. ..." && actual == "Mi.CachePolicy");
1013    }
1014
1015    #[test]
1016    fn test_verify_match_wrong_type() {
1017        let mtch = expression_match("5 + 4");
1018        let (mut verifier, context) = verifier();
1019        let result = verifier
1020            .visit_expression_match(&mtch, context)
1021            .expect_err("Could verify PS expression match with incorrect MEL type");
1022
1023        assert_matches!(
1024            *result,
1025            VerificationError::ExpressionWrongType(Type::Boolean, Type::Integer)
1026        )
1027    }
1028
1029    #[test]
1030    fn test_verify_request_transform_uri_expr_wrong_type() {
1031        let xform = request_transform(None, Some("5+4".to_string()), Some(true));
1032        let (mut verifier, context) = verifier();
1033        let result = verifier
1034            .visit_request_transform(&xform, context)
1035            .expect_err("Could verify PS with incorrect MEL type of expression to calculate URI");
1036
1037        assert_matches!(
1038            *result,
1039            VerificationError::ExpressionWrongType(Type::String, Type::Integer)
1040        );
1041    }
1042
1043    #[test]
1044    fn test_verify_response_transform() {
1045        let xform = response_transform(None, Some("404".to_string()), None, None);
1046        let (mut verifier, context) = verifier();
1047        let result = verifier
1048            .visit_response_transform(&xform, context)
1049            .expect("Could not verify correct PS")
1050            .value
1051            .expect("No value in PS Verification Context");
1052
1053        assert_matches!(
1054            result,
1055            PsVerifierContextValue::ResponseTransform(TypedResponseTransform {
1056                tpe: _,
1057                value: ResponseTransform {
1058                    xform: _,
1059                    response_status: _,
1060                    response_status_expr: None,
1061                    synthetic: None,
1062                    aug: PsVerificationKey::None
1063                }
1064            })
1065        );
1066    }
1067
1068    #[test]
1069    fn test_verify_response_transform_rs_expr() {
1070        let xform = response_transform(None, Some("400+4".to_string()), Some(true), None);
1071        let (mut verifier, context) = verifier();
1072        let result = verifier
1073            .visit_response_transform(&xform, context)
1074            .expect("Could not verify correct PS")
1075            .value
1076            .expect("No value in PS Verification Context");
1077
1078        assert_matches!(
1079            result,
1080            PsVerifierContextValue::ResponseTransform(TypedResponseTransform {
1081                tpe: _,
1082                value: ResponseTransform {
1083                    xform: _,
1084                    response_status: _,
1085                    response_status_expr: Some(true),
1086                    synthetic: None,
1087                    aug: PsVerificationKey::Expr(BinaryExpr(_))
1088                }
1089            })
1090        );
1091    }
1092    #[test]
1093    fn test_verify_response_transform_rs_expr_wrong_type() {
1094        let xform = response_transform(None, Some("false".to_string()), Some(true), None);
1095        let (mut verifier, context) = verifier();
1096        let result = verifier
1097            .visit_response_transform(&xform, context)
1098            .expect_err("Could verify PS response transform with incorrect MEL type of expression to calculate response status");
1099
1100        assert_matches!(
1101            *result,
1102            VerificationError::ExpressionWrongType(Type::Integer, Type::Boolean)
1103        );
1104    }
1105
1106    #[test]
1107    fn test_verify_header_transform() {
1108        let header_to_add = typed_header("add", "value", None);
1109        let header_to_replace = typed_header("replace", "value", None);
1110        let header_to_delete = vec!["delete1".to_string(), "delete2".to_string()];
1111
1112        let header_xform = header_transform(
1113            Some(header_to_delete),
1114            Some(vec![header_to_add]),
1115            Some(vec![header_to_replace]),
1116        );
1117
1118        let (mut verifier, context) = verifier();
1119        let result = verifier
1120            .visit_header_transform(&header_xform, context)
1121            .expect("Could not verify correct PS")
1122            .value
1123            .expect("No value in PS Verification Context");
1124
1125        assert_matches!(
1126            &result,
1127            PsVerifierContextValue::HeaderTransform(TypedHeaderTransform {
1128                        tpe: _,
1129                        value: HeaderTransform {
1130                            delete: Some(d),
1131                            add: Some(a),
1132                            replace: Some(b),
1133                            aug: PsVerificationKey::None
1134                        }
1135                    }) if d.len() == 2 && a.len() == 1 && b.len() == 1
1136        );
1137    }
1138
1139    #[test]
1140    fn test_verify_header_transform_value_expr() {
1141        let header_to_add = typed_header("add", "\"value\"", Some(true));
1142        let header_to_replace = typed_header("replace", "\"testing\" . \"one\"", Some(true));
1143
1144        let header_xform = header_transform(
1145            None,
1146            Some(vec![header_to_add]),
1147            Some(vec![header_to_replace]),
1148        );
1149
1150        let (mut verifier, context) = verifier();
1151        let result = verifier
1152            .visit_header_transform(&header_xform, context)
1153            .expect("Could not verify correct PS")
1154            .value
1155            .expect("No value in PS Verification Context");
1156
1157        assert_matches!(
1158            &result,
1159            PsVerifierContextValue::HeaderTransform(TypedHeaderTransform {
1160                        tpe: _,
1161                        value: HeaderTransform {
1162                            delete: None,
1163                            add: Some(a),
1164                            replace: Some(b),
1165                            aug: PsVerificationKey::None
1166                        }
1167            }) if matches!(a[0].value.aug, PsVerificationKey::Expr(_)) && matches!(b[0].value.aug, PsVerificationKey::Expr(_))
1168        );
1169    }
1170
1171    #[test]
1172    fn test_verify_header_transform_value_expr_wrong_type_add() {
1173        let header_to_add = typed_header("add", "5", Some(true));
1174        let header_to_replace = typed_header("replace", "\"testing\"", Some(true));
1175
1176        let header_xform = header_transform(
1177            None,
1178            Some(vec![header_to_add]),
1179            Some(vec![header_to_replace]),
1180        );
1181
1182        let (mut verifier, context) = verifier();
1183        let result = verifier
1184            .visit_header_transform(&header_xform, context)
1185            .expect_err("Could verify PS typed header with incorrect MEL type of expression to calculate header value");
1186
1187        assert_matches!(
1188            *result,
1189            VerificationError::ExpressionWrongType(Type::String, Type::Integer)
1190        );
1191    }
1192
1193    #[test]
1194    fn test_verify_header_transform_value_expr_wrong_type_replace() {
1195        let header_to_add = typed_header("add", "\"value\"", Some(true));
1196        let header_to_replace = typed_header("replace", "true", Some(true));
1197
1198        let header_xform = header_transform(
1199            None,
1200            Some(vec![header_to_add]),
1201            Some(vec![header_to_replace]),
1202        );
1203
1204        let (mut verifier, context) = verifier();
1205        let result = verifier
1206            .visit_header_transform(&header_xform, context)
1207            .expect_err("Could verify PS typed header with incorrect MEL type of expression to calculate header value");
1208
1209        assert_matches!(
1210            *result,
1211            VerificationError::ExpressionWrongType(Type::String, Type::Boolean)
1212        );
1213    }
1214
1215    #[test]
1216    fn test_verify_synthetic_response() {
1217        let header_to_add = typed_header("add", "value", None);
1218        let header_to_replace = typed_header("replace", "value", None);
1219        let headers = Some(vec![header_to_add, header_to_replace]);
1220
1221        let srt = synthetic_response(headers, None, None, None, None);
1222
1223        let (mut verifier, context) = verifier();
1224        let result = verifier
1225            .visit_synthetic_response(&srt, context)
1226            .expect("Could not verify correct PS")
1227            .value
1228            .expect("No value in PS Verification Context");
1229
1230        assert_matches!(
1231            &result,
1232            PsVerifierContextValue::SyntheticResponse(TypedSyntheticResponse {
1233                tpe: _,
1234                value: SyntheticResponse {
1235                    headers: _,
1236                    response_status: _,
1237                    response_status_expr: _,
1238                    body: _,
1239                    body_expr: _,
1240                    aug: PsVerificationKey::ExprPair(None, None)
1241                }
1242            })
1243        )
1244    }
1245
1246    #[test]
1247    fn test_verify_synthetic_response_response_expr() {
1248        let header_to_add = typed_header("add", "value", None);
1249        let header_to_replace = typed_header("replace", "value", None);
1250        let headers = Some(vec![header_to_add, header_to_replace]);
1251
1252        let srt = synthetic_response(headers, Some("400 + 4".to_string()), Some(true), None, None);
1253
1254        let (mut verifier, context) = verifier();
1255        let result = verifier
1256            .visit_synthetic_response(&srt, context)
1257            .expect("Could not verify correct PS")
1258            .value
1259            .expect("No value in PS Verification Context");
1260
1261        assert_matches!(
1262            &result,
1263            PsVerifierContextValue::SyntheticResponse(TypedSyntheticResponse {
1264                tpe: _,
1265                value: SyntheticResponse {
1266                    headers: _,
1267                    response_status: _,
1268                    response_status_expr: _,
1269                    body: _,
1270                    body_expr: _,
1271                    aug: PsVerificationKey::ExprPair(Some(_), None)
1272                }
1273            })
1274        )
1275    }
1276
1277    #[test]
1278    fn test_verify_synthetic_response_body_expr() {
1279        let header_to_add = typed_header("add", "value", None);
1280        let header_to_replace = typed_header("replace", "value", None);
1281        let headers = Some(vec![header_to_add, header_to_replace]);
1282
1283        let srt = synthetic_response(
1284            headers,
1285            None,
1286            None,
1287            Some("\"testing\"".to_string()),
1288            Some(true),
1289        );
1290
1291        let (mut verifier, context) = verifier();
1292        let result = verifier
1293            .visit_synthetic_response(&srt, context)
1294            .expect("Could not verify correct PS")
1295            .value
1296            .expect("No value in PS Verification Context");
1297
1298        assert_matches!(
1299            &result,
1300            PsVerifierContextValue::SyntheticResponse(TypedSyntheticResponse {
1301                tpe: _,
1302                value: SyntheticResponse {
1303                    headers: _,
1304                    response_status: _,
1305                    response_status_expr: _,
1306                    body: _,
1307                    body_expr: _,
1308                    aug: PsVerificationKey::ExprPair(None, Some(_))
1309                }
1310            })
1311        )
1312    }
1313
1314    #[test]
1315    fn test_verify_synthetic_response_body_and_response_expr() {
1316        let header_to_add = typed_header("add", "value", None);
1317        let header_to_replace = typed_header("replace", "value", None);
1318        let headers = Some(vec![header_to_add, header_to_replace]);
1319
1320        let srt = synthetic_response(
1321            headers,
1322            Some("400 + 4".to_string()),
1323            Some(true),
1324            Some("\"testing\"".to_string()),
1325            Some(true),
1326        );
1327
1328        let (mut verifier, context) = verifier();
1329        let result = verifier
1330            .visit_synthetic_response(&srt, context)
1331            .expect("Could not verify correct PS")
1332            .value
1333            .expect("No value in PS Verification Context");
1334
1335        assert_matches!(
1336            &result,
1337            PsVerifierContextValue::SyntheticResponse(TypedSyntheticResponse {
1338                tpe: _,
1339                value: SyntheticResponse {
1340                    headers: _,
1341                    response_status: _,
1342                    response_status_expr: _,
1343                    body: _,
1344                    body_expr: _,
1345                    aug: PsVerificationKey::ExprPair(Some(_), Some(_))
1346                }
1347            })
1348        )
1349    }
1350
1351    #[test]
1352    fn test_verify_synthetic_response_wrong_response_expr_type() {
1353        let header_to_add = typed_header("add", "value", None);
1354        let header_to_replace = typed_header("replace", "value", None);
1355        let headers = Some(vec![header_to_add, header_to_replace]);
1356
1357        let srt = synthetic_response(headers, Some("true".to_string()), Some(true), None, None);
1358
1359        let (mut verifier, context) = verifier();
1360        let result = verifier
1361            .visit_synthetic_response(&srt, context)
1362            .expect_err("Could verify PS synthetic response with incorrect MEL type of expression to calculate response");
1363
1364        assert_matches!(
1365            *result,
1366            VerificationError::ExpressionWrongType(Type::Integer, Type::Boolean)
1367        );
1368    }
1369
1370    #[test]
1371    fn test_verify_synthetic_response_wrong_body_expr_type() {
1372        let header_to_add = typed_header("add", "value", None);
1373        let header_to_replace = typed_header("replace", "value", None);
1374        let headers = Some(vec![header_to_add, header_to_replace]);
1375
1376        let srt = synthetic_response(headers, None, None, Some("true".to_string()), Some(true));
1377
1378        let (mut verifier, context) = verifier();
1379        let result = verifier
1380            .visit_synthetic_response(&srt, context)
1381            .expect_err("Could verify PS synthetic response with incorrect MEL type of expression to calculate body");
1382
1383        assert_matches!(
1384            *result,
1385            VerificationError::ExpressionWrongType(Type::String, Type::Boolean)
1386        );
1387    }
1388}
1389
1390#[cfg(test)]
1391mod test_verify_from_json {
1392    use std::assert_matches;
1393
1394    use crate::cdni::ps::spec::{
1395        HeaderTransform, ResponseTransform, SyntheticResponse, TypedGenericStage,
1396        TypedHeaderTransform, TypedStage, TypedSyntheticResponse,
1397    };
1398    use crate::environment::scope::Scopes;
1399    use crate::mel::types::Type;
1400    use crate::tests::read_test_file;
1401    use crate::verifying::ps::verify::VerificationError::{
1402        ExpressionWrongType, WrongGenericMetadataTypeName,
1403    };
1404    use crate::verifying::ps::verify::{PsVerificationKey, verify_ps, verify_ps_request_stage};
1405    use crate::{
1406        cdni::ps::spec::{
1407            RequestTransform, TypedProcessingStages, TypedRequestTransform, TypedResponseTransform,
1408        },
1409        mel::ast::Expr::BinaryExpr,
1410    };
1411
1412    use std::path::Path;
1413
1414    #[test]
1415    fn test_verify_simple() {
1416        let json = read_test_file(Path::new(
1417            "./tests/data/processing/simple/deserialize_verify.json",
1418        ));
1419        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1420            .expect("Could not parse JSON test file");
1421
1422        let result = verify_ps(&stages).expect("Could not verify proper PS");
1423
1424        let result_serialized =
1425            serde_json::to_string_pretty(&result).expect("Could not serialize verified PS");
1426        pretty_assertions::assert_eq!(json, result_serialized);
1427    }
1428
1429    #[test]
1430    fn test_verify_bad_generic_md_typename() {
1431        let json = read_test_file(Path::new(
1432            "./tests/data/processing/generic_metadata/bad-typename.json",
1433        ));
1434        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1435            .expect("Could not parse JSON test file");
1436
1437        let result = verify_ps(&stages)
1438            .expect_err("Could verify CDNI generic metadata with invalid metadata type name");
1439
1440        assert_matches!(*result, WrongGenericMetadataTypeName(expected, actual) if expected == "MI.ProcessingStages" && actual == "MI.ProcessigStages")
1441    }
1442
1443    #[test]
1444    fn test_verify_stage_metadata_with_generic_metadata_bad_type_name() {
1445        let json = read_test_file(Path::new(
1446            "./tests/data/processing/generic_metadata/bad-typename2.json",
1447        ));
1448        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1449            .expect("Could not parse JSON test file");
1450
1451        let result = verify_ps(&stages).expect_err("Could verify mistyped PS");
1452
1453        assert_matches!(*result, WrongGenericMetadataTypeName(expected, actual) if expected == "MI. ..." && actual == "Mi.CachePolicy");
1454    }
1455
1456    #[test]
1457    fn test_verify_match_wrong_type() {
1458        let json = read_test_file(Path::new(
1459            "./tests/data/processing/stage_rules/wrong_match_type.json",
1460        ));
1461        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1462            .expect("Could not parse JSON test file");
1463
1464        let result = verify_ps(&stages)
1465            .expect_err("Could verify PS expression match with incorrect MEL type");
1466
1467        assert_matches!(*result, ExpressionWrongType(Type::Boolean, Type::Integer))
1468    }
1469
1470    #[test]
1471    fn test_verify_request_transform() {
1472        let json = read_test_file(Path::new(
1473            "./tests/data/processing/request_transform/uri_no_expr.json",
1474        ));
1475        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1476            .expect("Could not parse JSON test file");
1477
1478        let result = verify_ps(&stages).expect("Could not verify correct PS");
1479
1480        assert_matches!(
1481            result.value.client_req[0]
1482                .value
1483                .stage_metadata
1484                .value
1485                .request_xform,
1486            Some(TypedRequestTransform {
1487                tpe: _,
1488                value: RequestTransform {
1489                    xform: _,
1490                    uri: _,
1491                    uri_is_expr: Some(false),
1492                    aug: PsVerificationKey::None
1493                }
1494            })
1495        );
1496    }
1497
1498    #[test]
1499    fn test_verify_request_transform_uri_expr() {
1500        let json = read_test_file(Path::new(
1501            "./tests/data/processing/request_transform/uri_expr.json",
1502        ));
1503        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1504            .expect("Could not parse JSON test file");
1505
1506        let result = verify_ps(&stages).expect("Could not verify correct PS");
1507
1508        assert_matches!(
1509            result.value.client_req[0]
1510                .value
1511                .stage_metadata
1512                .value
1513                .request_xform,
1514            Some(TypedRequestTransform {
1515                tpe: _,
1516                value: RequestTransform {
1517                    xform: _,
1518                    uri: _,
1519                    uri_is_expr: Some(true),
1520                    aug: PsVerificationKey::Expr(BinaryExpr(_))
1521                }
1522            })
1523        );
1524    }
1525
1526    #[test]
1527    fn test_verify_request_transform_uri_expr_wrong_type() {
1528        let json = read_test_file(Path::new(
1529            "./tests/data/processing/request_transform/uri_expr_wrong_type.json",
1530        ));
1531        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1532            .expect("Could not parse JSON test file");
1533
1534        let result = verify_ps(&stages)
1535            .expect_err("Could verify PS with incorrect MEL type of expression to calculate URI");
1536
1537        assert_matches!(*result, ExpressionWrongType(Type::String, Type::Integer));
1538    }
1539
1540    #[test]
1541    fn test_verify_response_transform() {
1542        let json = read_test_file(Path::new(
1543            "./tests/data/processing/response_transform/rs_no_expr.json",
1544        ));
1545        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1546            .expect("Could not parse JSON test file");
1547
1548        let result = verify_ps(&stages).expect("Could not verify correct PS");
1549
1550        assert_matches!(
1551            result.value.client_req[0]
1552                .value
1553                .stage_metadata
1554                .value
1555                .response_xform,
1556            Some(TypedResponseTransform {
1557                tpe: _,
1558                value: ResponseTransform {
1559                    xform: _,
1560                    response_status: _,
1561                    response_status_expr: None,
1562                    synthetic: None,
1563                    aug: PsVerificationKey::None
1564                }
1565            })
1566        );
1567    }
1568
1569    #[test]
1570    fn test_verify_response_transform_rs_expr() {
1571        let json = read_test_file(Path::new(
1572            "./tests/data/processing/response_transform/rs_expr.json",
1573        ));
1574        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1575            .expect("Could not parse JSON test file");
1576
1577        let result = verify_ps(&stages).expect("Could not verify correct PS");
1578
1579        assert_matches!(
1580            result.value.client_req[0]
1581                .value
1582                .stage_metadata
1583                .value
1584                .response_xform,
1585            Some(TypedResponseTransform {
1586                tpe: _,
1587                value: ResponseTransform {
1588                    xform: _,
1589                    response_status: _,
1590                    response_status_expr: Some(true),
1591                    synthetic: None,
1592                    aug: PsVerificationKey::Expr(BinaryExpr(_))
1593                }
1594            })
1595        );
1596    }
1597
1598    #[test]
1599    fn test_verify_response_transform_rs_expr_wrong_type() {
1600        let json = read_test_file(Path::new(
1601            "./tests/data/processing/response_transform/rs_expr_wrong_type.json",
1602        ));
1603        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1604            .expect("Could not parse JSON test file");
1605
1606        let result = verify_ps(&stages)
1607            .expect_err("Could verify PS response transform with incorrect MEL type of expression to calculate response status");
1608
1609        assert_matches!(*result, ExpressionWrongType(Type::Integer, Type::Boolean));
1610    }
1611
1612    #[test]
1613    fn test_verify_header_transform() {
1614        let json = read_test_file(Path::new(
1615            "./tests/data/processing/header_transform/value_no_expr.json",
1616        ));
1617        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1618            .expect("Could not parse JSON test file");
1619
1620        let result = verify_ps(&stages).expect("Could not verify correct PS");
1621
1622        assert_matches!(
1623            &result.value.client_req[0]
1624                .value
1625                .stage_metadata
1626                .value
1627                .response_xform,
1628            Some(TypedResponseTransform {
1629                tpe: _,
1630                value: ResponseTransform {
1631                    xform: Some(TypedHeaderTransform {
1632                        tpe: _,
1633                        value: HeaderTransform {
1634                            delete: Some(d),
1635                            add: Some(a),
1636                            replace: Some(b),
1637                            aug: PsVerificationKey::None
1638                        }
1639                    }),
1640                    response_status: _,
1641                    response_status_expr: None,
1642                    synthetic: None,
1643                    aug: PsVerificationKey::None
1644                }
1645            }) if d.len() == 2 && a.len() == 1 && b.len() == 1
1646        );
1647    }
1648
1649    #[test]
1650    fn test_verify_header_transform_value_expr() {
1651        let json = read_test_file(Path::new(
1652            "./tests/data/processing/header_transform/value_expr.json",
1653        ));
1654        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1655            .expect("Could not parse JSON test file");
1656
1657        let result = verify_ps(&stages).expect("Could not verify correct PS");
1658
1659        assert_matches!(
1660            &result.value.client_req[0]
1661                .value
1662                .stage_metadata
1663                .value
1664                .response_xform,
1665            Some(TypedResponseTransform {
1666                tpe: _,
1667                value: ResponseTransform {
1668                    xform: Some(TypedHeaderTransform {
1669                        tpe: _,
1670                        value: HeaderTransform {
1671                            delete: _,
1672                            add: Some(a),
1673                            replace: Some(b),
1674                            aug: PsVerificationKey::None
1675                        }
1676                    }),
1677                    response_status: _,
1678                    response_status_expr: None,
1679                    synthetic: None,
1680                    aug: PsVerificationKey::None
1681                }
1682            }) if matches!(a[0].value.aug, PsVerificationKey::Expr(_)) && matches!(b[0].value.aug, PsVerificationKey::Expr(_))
1683        );
1684    }
1685
1686    #[test]
1687    fn test_verify_header_transform_value_expr_wrong_type_add() {
1688        let json = read_test_file(Path::new(
1689            "./tests/data/processing/header_transform/value_expr_wrong_type.json",
1690        ));
1691        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1692            .expect("Could not parse JSON test file");
1693
1694        let result = verify_ps(&stages)
1695            .expect_err("Could verify PS typed header with incorrect MEL type of expression to calculate header value");
1696
1697        assert_matches!(*result, ExpressionWrongType(Type::String, Type::Boolean));
1698    }
1699
1700    #[test]
1701    fn test_verify_header_transform_value_expr_wrong_type_replace() {
1702        let json = read_test_file(Path::new(
1703            "./tests/data/processing/header_transform/value_expr_wrong_type_replace.json",
1704        ));
1705        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1706            .expect("Could not parse JSON test file");
1707
1708        let result =
1709            verify_ps(&stages).expect_err("Could verify PS with invalid metadata type name");
1710        assert_matches!(*result, ExpressionWrongType(Type::String, Type::Boolean));
1711    }
1712
1713    #[test]
1714    fn test_verify_synthetic_response() {
1715        let json = read_test_file(Path::new(
1716            "./tests/data/processing/synthetic_response/no_expr.json",
1717        ));
1718        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1719            .expect("Could not parse JSON test file");
1720
1721        let result = verify_ps(&stages).expect("Could not verify correct PS");
1722
1723        assert_matches!(
1724            &result.value.client_req[0]
1725                .value
1726                .stage_metadata
1727                .value
1728                .response_xform,
1729            Some(TypedResponseTransform {
1730                tpe: _,
1731                value: ResponseTransform {
1732                    xform: None,
1733                    response_status: _,
1734                    response_status_expr: _,
1735                    synthetic: Some(TypedSyntheticResponse {
1736                        tpe: _,
1737                        value: SyntheticResponse {
1738                            headers: _,
1739                            response_status: _,
1740                            response_status_expr: _,
1741                            body: _,
1742                            body_expr: _,
1743                            aug: PsVerificationKey::ExprPair(None, None)
1744                        }
1745                    }),
1746                    aug: PsVerificationKey::None
1747                }
1748            })
1749        );
1750    }
1751
1752    #[test]
1753    fn test_verify_synthetic_response_response_expr() {
1754        let json = read_test_file(Path::new(
1755            "./tests/data/processing/synthetic_response/response_expr.json",
1756        ));
1757        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1758            .expect("Could not parse JSON test file");
1759
1760        let result = verify_ps(&stages).expect("Could not verify correct PS");
1761
1762        assert_matches!(
1763            &result.value.client_req[0]
1764                .value
1765                .stage_metadata
1766                .value
1767                .response_xform,
1768            Some(TypedResponseTransform {
1769                tpe: _,
1770                value: ResponseTransform {
1771                    xform: None,
1772                    response_status: _,
1773                    response_status_expr: _,
1774                    synthetic: Some(TypedSyntheticResponse {
1775                        tpe: _,
1776                        value: SyntheticResponse {
1777                            headers: _,
1778                            response_status: _,
1779                            response_status_expr: _,
1780                            body: _,
1781                            body_expr: _,
1782                            aug: PsVerificationKey::ExprPair(Some(_), None)
1783                        }
1784                    }),
1785                    aug: PsVerificationKey::None
1786                }
1787            })
1788        );
1789    }
1790
1791    #[test]
1792    fn test_verify_synthetic_response_body_expr() {
1793        let json = read_test_file(Path::new(
1794            "./tests/data/processing/synthetic_response/body_expr.json",
1795        ));
1796        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1797            .expect("Could not parse JSON test file");
1798
1799        let result = verify_ps(&stages).expect("Could not verify correct PS");
1800
1801        assert_matches!(
1802            &result.value.client_req[0]
1803                .value
1804                .stage_metadata
1805                .value
1806                .response_xform,
1807            Some(TypedResponseTransform {
1808                tpe: _,
1809                value: ResponseTransform {
1810                    xform: None,
1811                    response_status: _,
1812                    response_status_expr: _,
1813                    synthetic: Some(TypedSyntheticResponse {
1814                        tpe: _,
1815                        value: SyntheticResponse {
1816                            headers: _,
1817                            response_status: _,
1818                            response_status_expr: _,
1819                            body: _,
1820                            body_expr: _,
1821                            aug: PsVerificationKey::ExprPair(None, Some(_))
1822                        }
1823                    }),
1824                    aug: PsVerificationKey::None
1825                }
1826            })
1827        );
1828    }
1829
1830    #[test]
1831    fn test_verify_synthetic_response_body_and_response_expr() {
1832        let json = read_test_file(Path::new(
1833            "./tests/data/processing/synthetic_response/both_body_response_exprs.json",
1834        ));
1835        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1836            .expect("Could not parse JSON test file");
1837
1838        let result = verify_ps(&stages).expect("Could not verify correct PS");
1839
1840        assert_matches!(
1841            &result.value.client_req[0]
1842                .value
1843                .stage_metadata
1844                .value
1845                .response_xform,
1846            Some(TypedResponseTransform {
1847                tpe: _,
1848                value: ResponseTransform {
1849                    xform: None,
1850                    response_status: _,
1851                    response_status_expr: _,
1852                    synthetic: Some(TypedSyntheticResponse {
1853                        tpe: _,
1854                        value: SyntheticResponse {
1855                            headers: _,
1856                            response_status: _,
1857                            response_status_expr: _,
1858                            body: _,
1859                            body_expr: _,
1860                            aug: PsVerificationKey::ExprPair(Some(_), Some(_))
1861                        }
1862                    }),
1863                    aug: PsVerificationKey::None
1864                }
1865            })
1866        );
1867    }
1868
1869    #[test]
1870    fn test_verify_synthetic_response_wrong_response_expr_type() {
1871        let json = read_test_file(Path::new(
1872            "./tests/data/processing/synthetic_response/response_expr_wrong_type.json",
1873        ));
1874        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1875            .expect("Could not parse JSON test file");
1876
1877        let result = verify_ps(&stages)
1878            .expect_err("Could verify PS synthetic response with incorrect MEL type of expression to calculate response");
1879
1880        assert_matches!(*result, ExpressionWrongType(Type::Integer, Type::String));
1881    }
1882
1883    #[test]
1884    fn test_verify_synthetic_response_wrong_body_expr_type() {
1885        let json = read_test_file(Path::new(
1886            "./tests/data/processing/synthetic_response/body_expr_wrong_type.json",
1887        ));
1888        let stages = serde_json::from_str::<TypedProcessingStages<()>>(&json)
1889            .expect("Could not parse JSON test file");
1890
1891        let result = verify_ps(&stages)
1892            .expect_err("Could verify PS synthetic response with incorrect MEL type of expression to calculate body");
1893
1894        assert_matches!(*result, ExpressionWrongType(Type::String, Type::Boolean));
1895    }
1896
1897    #[test]
1898    fn test_verify_client_request_stage() {
1899        let json = read_test_file(Path::new(
1900            "./tests/data/processing/client_request_stage/if.json",
1901        ));
1902        let stages = serde_json::from_str::<TypedGenericStage>(&json)
1903            .expect("Could not parse JSON test file");
1904
1905        let result = verify_ps_request_stage(&stages, &Scopes::<Type>::default())
1906            .expect("Could not verify PS client request stage");
1907
1908        assert_matches!(result, TypedStage::ClientRequest(_))
1909    }
1910
1911    #[test]
1912    fn test_verify_client_request_stage_request_response_header_transform() {
1913        let json = read_test_file(Path::new(
1914            "./tests/data/processing/client_request_stage/request_response_header_transform.json",
1915        ));
1916        let stages = serde_json::from_str::<TypedGenericStage>(&json)
1917            .expect("Could not parse JSON test file");
1918
1919        let result = verify_ps_request_stage(&stages, &Scopes::<Type>::default())
1920            .expect("Could not verify PS client request stage");
1921
1922        assert_matches!(result, TypedStage::ClientRequest(_))
1923    }
1924}