clips

My CLIPS program isn't reading user input properly


This is my program:

Is a program that gives questions on what kind of vulnerability scanning tool is best recommended based on user input.

Tried my best to add ways of checking what parts of the code were checking properly but found no luck in actually storing user preference and printing the appropriate scanner reccommendation

No matter what input I tried, only got No scanner reccommendation.

Believe it might be because it's rule is based on progress and scanner reccommendation just isn't storing correctly?

(deftemplate user-preference
  (slot scan-type (type SYMBOL))
  (slot environment (type SYMBOL)))

(deftemplate scanner-recommendation
  (slot scanner-name (type STRING))
  (slot description (type STRING)))

(deftemplate question-progress
  (slot stage (type SYMBOL)))

;; Initialize question stage
(defrule initialize-question-stage
  (not (question-progress))
  =>
  (assert (question-progress (stage next)))
  (printout t "Initialization complete. Stage set to 'next'." crlf))

;; Rule to ask initial scan type
(defrule ask-scan-type
  (not (user-preference (scan-type ?))) 
  ?f <- (question-progress (stage next)) 
  =>
  (printout t "What type of scan are you interested in? (webapp/network/cloud/infrastructure): " crlf)
  (bind ?input (read))
  (if (or (eq ?input webapp) (eq ?input network) (eq ?input cloud) (eq ?input infrastructure)) then
    (assert (user-preference (scan-type ?input)))
    (printout t "Scan type set to: " ?input crlf)
    (retract ?f)
    (assert (question-progress (stage follow-up)))
  else
    (printout t "Invalid input. Please enter 'webapp', 'network', 'cloud', or 'infrastructure'." crlf)
    (retract ?f)
    (assert (question-progress (stage next)))))

;; Ask environment for webapp scans
(defrule ask-webapp-environment
  (user-preference (scan-type webapp))
  ?f <- (question-progress (stage follow-up))
  =>
  (printout t "Are you looking for a comprehensive or entry-level webapp scanner? " crlf)
  (bind ?input (read))
  (if (or (eq ?input comprehensive) (eq ?input entry-level)) then
    (assert (user-preference (environment ?input)))
    (printout t "Environment set to: " ?input crlf)
    (retract ?f)
    (assert (question-progress (stage complete)))
  else
    (printout t "Invalid input. Please enter 'comprehensive' or 'entry-level'." crlf)))

;; Ask environment for network scans
(defrule ask-network-environment
  (user-preference (scan-type network))
  ?f <- (question-progress (stage follow-up))
  =>
  (printout t "Do you prefer deep or fast network scanning? " crlf)
  (bind ?input (read))
  (if (or (eq ?input deep) (eq ?input fast)) then
    (assert (user-preference (environment ?input)))
    (printout t "Environment set to: " ?input crlf)
    (retract ?f)
    (assert (question-progress (stage complete)))
  else
    (printout t "Invalid input. Please enter 'deep' or 'fast'." crlf)))

;; Ask environment for cloud scans
(defrule ask-cloud-environment
  (user-preference (scan-type cloud))
  ?f <- (question-progress (stage follow-up))
  =>
  (printout t "Are you focused on cloud security or container security? " crlf)
  (bind ?input (read))
  (if (or (eq ?input cloud) (eq ?input container)) then
    (assert (user-preference (environment ?input)))
    (printout t "Environment set to: " ?input crlf)
    (retract ?f)
    (assert (question-progress (stage complete)))
  else
    (printout t "Invalid input. Please enter 'cloud' or 'container'." crlf)))

;; Ask environment for infrastructure scans
(defrule ask-infrastructure-environment
  (user-preference (scan-type infrastructure))
  ?f <- (question-progress (stage follow-up))
  =>
  (printout t "Is this for IT infrastructure or endpoint security? " crlf)
  (bind ?input (read))
  (if (or (eq ?input infrastructure) (eq ?input endpoint)) then
    (assert (user-preference (environment ?input)))
    (printout t "Environment set to: " ?input crlf)
    (retract ?f)
    (assert (question-progress (stage complete)))
  else
    (printout t "Invalid input. Please enter 'infrastructure' or 'endpoint'." crlf)))

;; Recommendations based on user input

;; Webapp scan recommendations
(defrule recommend-invicti
  (user-preference (scan-type webapp) (environment comprehensive))
  =>
  (assert (scanner-recommendation (scanner-name "Invicti")
                                  (description "Best for comprehensive webapp scanning.")))
  (printout t "Recommendation rule triggered for Invicti." crlf))

(defrule recommend-stackhawk
  (user-preference (scan-type webapp) (environment entry-level))
  =>
  (assert (scanner-recommendation (scanner-name "StackHawk")
                                  (description "Best entry-level scanner for webapp security.")))
  (printout t "Recommendation rule triggered for StackHawk." crlf))


;;; Other scan recommendations with same / similar code to Webapp scan reccommendations
;;; e.g. network, cloud and infrastructure


;; No solution if no scanner-recommendation is found
(defrule no-solution
  (question-progress (stage complete))
  (not (scanner-recommendation (scanner-name ?)))
  =>
  (printout t "No scanner recommendations based on your selections." crlf))

;; Output best solution if scanner recommendation exists
(defrule best-solution
  (question-progress (stage complete))
  (scanner-recommendation (scanner-name ?name) (description ?desc))
  =>
  (printout t "Recommended Scanner: " ?name crlf)
  (printout t "Description: " ?desc crlf))

Solution

  • When your program runs, you are creating two different user-preference facts, each with just one of the needed values:

    CLIPS> (reset)
    CLIPS> (run)
    Initialization complete. Stage set to 'next'.
    What type of scan are you interested in? (webapp/network/cloud/infrastructure): 
    webapp
    Scan type set to: webapp
    Are you looking for a comprehensive or entry-level webapp scanner? 
    comprehensive
    Environment set to: comprehensive
    No scanner recommendations based on your selections.
    CLIPS> (facts)
    f-2     (user-preference (scan-type webapp) (environment nil))
    f-4     (user-preference (scan-type nil) (environment comprehensive))
    f-5     (question-progress (stage complete))
    For a total of 3 facts.
    CLIPS> 
    

    Your recommend-invicti rule is expecting just one fact with both needed values:

    (defrule recommend-invicti
      (user-preference (scan-type webapp) (environment comprehensive))
      =>
      (assert (scanner-recommendation (scanner-name "Invicti")
                                      (description "Best for comprehensive webapp scanning.")))
      (printout t "Recommendation rule triggered for Invicti." crlf))
    

    Modify your rules so that you are assigning the appropriate values to just one fact:

    (defrule ask-webapp-environment
      ?u <- (user-preference (scan-type webapp))
      ?f <- (question-progress (stage follow-up))
      =>
      (printout t "Are you looking for a comprehensive or entry-level webapp scanner? " crlf)
      (bind ?input (read))
      (if (or (eq ?input comprehensive) (eq ?input entry-level)) then
        (modify ?u (environment ?input)) ; <- Change
        (printout t "Environment set to: " ?input crlf)
        (retract ?f)
        (assert (question-progress (stage complete)))
      else
        (printout t "Invalid input. Please enter 'comprehensive' or 'entry-level'." crlf)))