load content into demo and handle shell commands

This commit is contained in:
Victoria Jeffrey 2016-09-06 10:32:24 -04:00 committed by Christoph Hartmann
parent 4048cc6b4c
commit 66e54b675f
56 changed files with 963 additions and 233 deletions

2
.gitignore vendored
View file

@ -15,4 +15,4 @@ omnibus/pkg
www/tutorial/typings
www/tutorial/node_modules
www/tutorial/**/*.js.map
www/tutorial/**/*.js
www/tutorial/dist

View file

@ -1,20 +1,85 @@
# encoding: utf-8
require 'train'
require 'yaml'
require 'json'
require 'shellwords'
commands = { 'inspec_exec' => 'inspec exec examples/profile/controls/example.rb', 'inspec_version' => 'inspec version', 'help' => 'inspec help' }
# Load all commands and instructions
demos = YAML.load(File.read('www/tutorial/tutorial.yml'))['demos']
commands = demos.map { |x| x['desc'] }.map { |x| x.scan(/```(.*?)```/m) }.flatten.map(&:strip).map { |x| x.split("\n") }
tutorial_instructions = demos.map { |x| [x['demo'], x['desc']] }
extra_commands = YAML.load(File.read('www/tutorial/commands.yml'))['commands']
# find out if we have a single command or a multiline shell command
cmds = commands.map { |x|
cmd = x.join("\n")
if cmd.include?('describe')
cmd
else
x
end
}
tutorial_commands = cmds.flatten
# Pull shell commands out so they can be handled
# This is currently done by checking if the command includes the word inspec :/
no_shell_tutorial_commands = tutorial_commands.select { |a| a.include?('inspec') }
shell_tutorial_commands = tutorial_commands.reject { |a| a.include?('inspec') }
# escape the shell commands for echo
shell_tutorial_commands.map! { |x|
Shellwords.escape(x)
}
# Add 'echo' and ' | inspec shell' to shell commands to enable inspec shell command functionality
shell_commands = shell_tutorial_commands.map { |x| 'echo ' + x + ' | inspec shell' }
# Merge the output
commands = no_shell_tutorial_commands + extra_commands + shell_commands
# TEMPORARY: REMOVE SSH COMMANDS (-t & -b)
commands.delete_if { |x| x.include? '-t' }
commands.delete_if { |x| x.include? '-b' }
# Create key given command
def create_key(command)
formatted_command = command.gsub(/\W/, '_')
not_too_long = formatted_command.gsub(/_{2,}/, '_')
not_too_long + '.txt'
end
# Create commands.json file
commands_file = File.new('www/tutorial/commands.json', 'w')
json = commands.map { |x| [x => create_key(x)] }.to_json
commands_file.write(json)
puts 'Wrote www/tutorial/commands.json'
# Create instructions.json file
instructions_file = File.new('www/tutorial/instructions.json', 'w')
instructions_file.write(tutorial_instructions.to_json)
puts 'Wrote www/tutorial/instructions.json'
# Create extra_commands.json file used to expose the extra commands
# that have been enabled but not noted in the tutorial instructions
extra_commands_file = File.new('www/tutorial/extra_commands.json', 'w')
extra_commands_file.write(extra_commands.to_json)
puts 'Wrote www/tutorial/extra_commands.json'
# Generate command results files
# Create Train connection
backend = Train.create('local')
conn = backend.connection
commands.each do |keyname, command|
# loop around commands
# Loop over commands
commands.each do |command|
cmd = conn.run_command(command)
cmd.stdout
# save the result and put it in inspec/www/app/results with the keyname as filename
# save the result and put it in inspec/www/app/results with command as filename
result = cmd.stdout
dir = 'www/tutorial/app/responses/'
filename = File.join(dir, "#{keyname}.txt")
key = create_key(command)
filename = File.join(dir, key.to_s)
out_file = File.new(filename, 'w')
result.lines.each do |line|
line_to_write = "#{line.chomp}\r\n"

View file

@ -10,4 +10,6 @@ npm-debug.log
app/*.js
app/*.map
app/**/*.js
app/**/*.map
app/**/*.map
!webpack.config.js

View file

@ -1,7 +1,58 @@
## InSpec Demo
# Welcome to the InSpec Tutorial
-----------------------------------------------------------
## The InSpec whaaaat? What is this thing?
This is an Angular 2 app that uses Xterm (https://github.com/sourcelair/xterm.js/) to simulate a terminal.
'Ok, but why?'
To give people an easy quick introduction to inspec and all it can do! Give it a try,
learn a thing or two, tell us what you'd like to know more about, and have fun exploring!
## How to run it
run `npm install` to load dependencies
run `npm run start` and browse to localhost:8080
run `npm run start` to open in your browser @ localhost:8080
To generate content for the app/responses folder,
run `bundle exec rake update demo` from the root of inspec project.
-----------------------------------------------------------
## How does it work???
Well, let me tell you a story of a file named `tutorial.yml`, who lives in a directory named `inspec/www/tutorial`.
This kind, informational file was full of content, and oh so desired to spread its knowledge.
But it knew not how to do so, for it was a simple yml file.
Then, from around the corner, came a sweet little ruby file, whose only wish was to help people
do the things they needed to do. It's name, in fact, was `command_simulator.rb`, and it lived in a
nearby directory named `inspec/tasks`. And, aha, a match was found.
And so command_simulator kindly took tutorialyml by the hand, and said 'let me help you! I can parse you, and help you help others'.
And thus it began...
command_simulator parsed tutorialyml to find the instructions and commands that are noted in the instructions.
After that, the real fun began: command_simulator worked and worked to format the commands and prepare them.
She created json files for instructions and commands, and used Train with MixLib:Shellout in the background to
run the commands and record the output to some .txt files in the `www/tutorial/app/responses` directory.
Pleased with her work, command_simulator turned to her friend the webapp, and said to her: 'take these json files, and show them to the people.'
Webapp then went and found her friend xterm, and said, why let's do this together, for two heads are always better than one!
And so webapp said to her dear friend angular2, please help me make this work! and angular2 came running, as friends always do.
And so angular2 met xterm, and as they shook hands, they knew they would be good friends together. So they put their heads together,
and made some decisions about what each one's role would be. Xterm claimed responsiblity for creating the terminal view,
reading the user's input, and displaying it. App then explained she could take that final user input sent over by xterm and
and transform it into a regular expression, which she could then use to match against the information in the commandsjson file,
matching the user's input against the key and then retrieving the associated value's txt file.
And it was so. :)
## How to generate content for tutorial/update the tutorial
To generate content for the tutorial, update the tutorial.yml and/or commands.yml file and
run `bundle exec rake update_demo` from the root of inspec project.
This will create/update two json files (commands.json and instructions.json)
and the .txt files for the app/responses/ directory (generated from the commands included in the tutorial.yml)
----------------------------------------------------------
### Author: Victoria Jeffrey

View file

@ -1,3 +1,7 @@
.main {
height: 100%;
}
.terminal-nav {
display: inline-block;
position: fixed;
@ -10,7 +14,6 @@
line-height: 60px;
font-size: 30px;
font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 300;
transition: all 200ms ease-in;
cursor: pointer;
z-index: 10;
@ -20,27 +23,45 @@
color: #ccc;
}
.guide {
font-family: monospace;
font-size: 1.2rem;
max-width: 1000px;
margin: auto;
margin-top: 1rem;
margin-bottom: 1rem;
padding: 1rem;
background-color: #444;
img {
width: 200px;
height: 50px;
padding-bottom: 5px;
}
a {
color: lightskyblue;
text-decoration: none;
.guide {
-webkit-font-smoothing: antialiased;
color: #DDDDDD;
font-family: monospace;
font-weight: 100;
font-size: 16px;
max-width: 1000px;
margin: auto;
padding: 1rem;
background-color: #444;
text-align: left;
line-height: 1.3;
}
.bold {
font-weight: bold;
}
p {
display: block;
}
pre {
white-space: pre-wrap;
}
.cli {
-webkit-font-smoothing: antialiased;
font-family: monospace;
font-size: 1.2rem;
white-space: pre-wrap;
word-wrap: break-word;
max-width: 1200px;
margin: auto;
height: 70%;
}

View file

@ -4,24 +4,14 @@
<span> x </span>
</div>
<div class="guide" *ngIf="counter === 0">
Welcome to the interactive InSpec demo!
<p>
This tutorial is great for getting familiar with InSpec. There are 3 sections:
</p>
<ol>
<!--TODO: give these real links-->
<li><a href="...">InSpec commandline interface</a></li>
<li><a href="...">InSpec interactive shell</a></li>
<li><a href="...">Create test and compliance profile</a></li>
</ol>
<p>Use the command "next" to move forward or "prev" to move backwards.</p>
</div>
<img src="inspec-logo.png" alt="Inspec Logo">
<div class="main">
<div class="guide">
<p class="bold">{{title}}</p>
<pre>{{instructions}}</pre>
</div>
<div class="guide" *ngIf="counter > 0">
<pre> {{ instructions }} </pre>
</div>
<div class="cli">
<xterm-terminal (command)="evalCommand(command=$event)" [responsesArray]="responsesArray" [response]="response" [shell]="shell"></xterm-terminal>
</div>
<div class="cli">
<xterm-terminal (command)="evalCommand(command=$event)" [response]="response" [shell]="shell"></xterm-terminal>
</div>
</div>

View file

@ -3,6 +3,8 @@ import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { HTTP_PROVIDERS } from '@angular/http';
import { XtermTerminalComponent } from './xterm-terminal/xterm-terminal.component';
declare var require: any;
var shellwords = require("shellwords");
@Component({
selector: 'my-app',
@ -13,20 +15,39 @@ import { XtermTerminalComponent } from './xterm-terminal/xterm-terminal.componen
})
export class AppComponent implements OnInit {
// template values
instructions: any;
instructionsArray: any;
responsesArray: any;
counter: number = 0;
title: string;
// taken as input by xterm terminal componen
response: string;
shell: string;
// colors for responses
red: string = " ";
white: string = " ";
black: string = " ";
matchFound: boolean; // helps to handle no match found response
counter: number = 0; // keeps track of step number count
userCommand: string; // used to display better error msg when no match is found
extraCmds: string = ''; // used to display extra commands available (from commands.yml)
// arrays of data parsed from json files
commandsArray: any = [];
instructionsArray: any = [];
constructor(private http: Http) { }
ngOnInit() {
// load json files
this.getInstructions();
this.getResponses();
this.getExtraCmds();
}
// called when command entered is 'next' or 'prev'
// modifies value of counter and calls displayInstructions
updateInstructions(step) {
let totalSteps = this.instructionsArray.length - 1;
let msg = Math.random();
@ -34,117 +55,187 @@ export class AppComponent implements OnInit {
if (this.counter < totalSteps) {
this.counter += 1;
}
this.response = ' Message: ' + msg;
this.response = this.black + 'next' + msg;
} else if (step === 'prev') {
if (this.counter > 0) {
this.counter -= 1;
}
this.response = ' Message: ' + msg;
this.response = this.black + 'prev' + msg;
}
this.instructions = this.instructionsArray[this.counter]['_body'];
this.displayInstructions();
}
// display instructions based on value of counter and
// format text to remove triple backticks. if the user has reached
// then end of the demo, display a message containing extra commands that have been
// enabled in the demo
displayInstructions() {
if (this.counter === this.instructionsArray.length - 1) {
this.title = "the end; that's all folks!";
this.instructions = "here are some other commands you can try out: \r\n\r\n" + this.extraCmds;
} else {
if (this.instructionsArray[this.counter][1]) {
this.title = this.instructionsArray[this.counter][0];
let text = this.instructionsArray[this.counter][1];
let formattedText = text.replace(/```/g, '');
this.instructions = formattedText;
} else {
this.instructions = 'Sorry, something seems to have gone wrong. Please try refreshing your browser.';
}
}
}
// called when a new value is emitted for command
// checks for a match, calls parseInspecShell if shell is inspec-shell
// and calls checkCommand if none of the first commands match
evalCommand(command) {
if (this.shell === 'inspec-shell') {
this.parseInspecShell(command);
}
else if (command.match(/^inspec\s*.*/)) {
this.parseInspecCommand(command);
}
else if (command.match(/^next\s*/)) {
this.userCommand = command;
if (command.match(/^next\s*/)) {
this.updateInstructions('next');
}
else if (command.match(/^prev\s*/)) {
this.updateInstructions('prev');
}
else if (this.shell === 'inspec-shell') {
this.parseInspecShell(command);
}
else if (command.match(/^ls\s*/)) {
this.response = " " + this.responsesArray[1]['_body'];
this.response = this.white + "README.md";
}
else if (command.match(/^pwd\s*/)) {
this.response = " " + this.responsesArray[2]['_body'];
this.response = this.white + "anonymous-web-user/inspec";
}
else if (command.match(/^cat\s*README.md\s*/i)) {
this.response = " Only a few commands are implemented in this terminal. Please follow the demo";
this.response = this.white + "Only a few commands are implemented in this terminal. Please follow the demo";
}
else if (command.match(/^less\s*README.md\s*/i)) {
this.response = " Only a few commands are implemented in this terminal. Please follow the demo.";
this.response = this.white + "Only a few commands are implemented in this terminal. Please follow the demo.";
}
else {
this.response = " invalid command: " + command;
}
}
parseInspecCommand(command) {
let command_target = command.match(/^inspec\s*(.*)/);
if (command_target[1] === 'shell') {
this.shell = 'inspec-shell'
this.response = " " + 'Welcome to the InSpec Shell\r\n To find out how to use it, type: help\r\n To leave, type: exit';
}
else if (command_target[1].match(/^exec\s*.*/)) {
this.parseInspecExec(command);
}
else if (command_target[1].match(/^version\s*/)) {
this.response = " " + this.responsesArray[4]['_body'];
}
else {
let msg = Math.random();
this.response = " " + this.responsesArray[0]['_body'] + " " + msg;
}
}
parseInspecExec(command) {
let target = command.match(/^inspec exec\s*(.*)/);
if (target[1] === 'examples/profile') {
this.response = " " + this.responsesArray[3]['_body'];
} else {
this.response = "  Could not fetch inspec profile in '" + target[1] + "' ";
this.checkCommand(command);
}
}
// if the shell is inspec-shell, we want to exit the shell env on 'exit'
// format the command for checkCommand by using shellwords.escape and
// adding 'echo' and 'inspec shell' to match command from commands.json
parseInspecShell(command) {
// exit inspec shell
if (command.match(/^exit\s*/)) {
this.shell = '';
this.response = '';
}
else if (command.match(/^ls\s*/)) {
this.response = " " + this.responsesArray[5]['_body'];
else if (command.match(/^pwd\s*/)) {
this.response = this.white + "anonymous-web-user/inspec-shell";
}
// TODO: functionality for inspec Shell
else {
this.response = " " + 'soon this will work, but not yet :) '
let escaped_cmd;
let formatted_cmd;
// TODO: make this better
// I don't really like what we're doing here when we have a
// describe and control block, but I had a lot of trouble getting this
// to work because of the new lines carriage returns in the command from commands.json
// so at the moment we're splitting the command on "do" and assuming a match if that first
// result group matches (everything before do) :/
if (command.match(/^describe.*|^control/)) {
let split_cmd = command.split('do');
escaped_cmd = shellwords.escape(split_cmd[0]);
formatted_cmd = 'echo.*' + escaped_cmd ;
} else {
escaped_cmd = shellwords.escape(command)
formatted_cmd = 'echo.*' + escaped_cmd + '.*inspec.*shell';
}
let regex_compatible = formatted_cmd.replace(/\W+/g, '.*');
this.checkCommand(regex_compatible);
}
}
// takes the command as input, replaces all white space with regex whitespace matcher
// and creates a new regex. check if the regex matches any of the keys in the commandsArray
// if it matches, we set matchFound to true and call displayResult. if it doesn't match,
// we display a default error message
checkCommand(command) {
let dir = 'app/responses/';
let cmd = command.replace(/ /g,"\\s*")
let regexcmd = new RegExp(('^'+cmd+'$'), 'm')
this.matchFound = false;
for (var i = 0; i < this.commandsArray.length; i++) {
let object = this.commandsArray[i]
for (let key in object) {
if (key.match(regexcmd)) {
this.matchFound = true;
let value = object[key];
this.http.get(dir + value).subscribe(data => {
this.displayResult(command, data);
},
err => console.error(err));
}
}
}
// if no match is found, we check if the command entered was inspec exec something
// and if it is respond appropriately ('could not fetch inspec profile in ''), otherwise
// respond with 'invalid command' and the command entered
if (this.matchFound === false) {
let msg = Math.random();
if (command.match(/^inspec exec\s*.*/)) {
let target = command.match(/^inspec exec\s*(.*)/)
if (target[1].match(/.*-t.*|.*-b.*/)) {
this.response = this.red + "Sorry, we haven't figured out how to handle the transport options in this demo just yet." + this.black + msg;
} else {
this.response = this.red + "Could not fetch inspec profile in '" + target[1] + "' " + this.black + msg;
}
} else {
this.response = this.red + 'invalid command: ' + this.userCommand + this.black + msg;
}
}
}
// if the command if inspec shell, we also need to set the shell variable to
// inspec shell. print response value and random msg (to ensure recognition of value change by xterm
// terminal component)
displayResult(command, data) {
if (command.match(/^inspec\s*shell\s*$/)) {
this.shell = 'inspec-shell';
}
let msg = Math.random();
this.response = this.white + data['_body'] + this.black + msg;
}
// load json file for instructions and save to instructionsArray
// call displayInstructions to load first set of instructions
getInstructions() {
Observable.forkJoin(
this.http.get('/app/instructions/step0.txt'),
this.http.get('/app/instructions/step1.txt'),
this.http.get('/app/instructions/step2.txt')
).subscribe(
data => {
this.instructionsArray = data;
this.updateInstructions(0);
this.http.get('instructions.json')
.subscribe(data => {
this.instructionsArray = JSON.parse(data['_body']);
this.displayInstructions();
},
err => console.error(err)
);
}
// load json file for commands and push each object to commandsArray
getResponses() {
Observable.forkJoin(
this.http.get('/app/responses/help.txt'), // 0
this.http.get('/app/responses/ls.txt'), // 1
this.http.get('/app/responses/pwd.txt'), // 2
this.http.get('/app/responses/inspec_exec.txt'), // 3
this.http.get('/app/responses/inspec_version.txt'), // 4
this.http.get('/app/responses/pwd_inspec_shell.txt') // 5
).subscribe(
data => {
this.responsesArray = data;
this.http.get('commands.json')
.subscribe(data => {
let result = JSON.parse(data['_body']);
for (var i = 0; i < result.length; i++) {
let object = result[i][0];
this.commandsArray.push(object);
}
},
err => console.error(err)
);
}
}
// load json file for extra commands to display extra commands available to user
getExtraCmds() {
this.http.get('extra_commands.json')
.subscribe(data => {
let result = JSON.parse(data['_body']);
for (var i = 0; i < result.length; i++) {
this.extraCmds += result[i] + "\r\n";
}
},
err => console.error(err)
);
}
}

View file

@ -1,11 +0,0 @@
<b>Welcome to the interactive InSpec demo!</b>
<p>
This tutorial is great for getting familiar with InSpec. There are 3 sections:
</p>
<ol>
<!--TODO: give these real links-->
<li><a href="...">InSpec commandline interface</a></li>
<li><a href="...">InSpec interactive shell</a></li>
<li><a href="...">Create test and compliance profile</a></li>
</ol>
<p><b>Use the command "next" to move forward</b> or "prev" to move backwards.</p>

View file

@ -1,7 +0,0 @@
Step 1
hey look we made it to step 1!
here are more things to do
talk to a frog, smell a flower
stare at the sky
and try typing 'inspec exec examples/profile'

View file

@ -1 +0,0 @@
whoa there! that's all the steps we got! go experiment @ 'https://github.com/chef/inspec'

View file

@ -0,0 +1,5 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> => "Darwin vjeffrey01 15.6.0 Darwin Kernel Version 15.6.0: Mon Aug 29 20:21:34 PDT 2016; root:xnu-3248.60.11~1/RELEASE_X86_64 x86_64\n"
inspec> 

View file

@ -0,0 +1,8 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> inspec>  inspec>  inspec>  inspec>  inspec>  inspec>   ✖ id: File /root mode should cmp "0750" (wrong number of arguments (1 for 0))
Summary: 0 successful, 1 failures, 0 skipped
inspec> 

View file

@ -0,0 +1,10 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> inspec>  inspec>  inspec> 
File /root
 ✖ should exist
expected File /root to exist
Summary: 0 successful, 2 failures, 0 skipped
inspec> 

View file

@ -0,0 +1,5 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> => nil
inspec> 

View file

@ -0,0 +1,27 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> Name: command
Description:
Use the command InSpec audit resource to test an arbitrary command that is run on the system.
Example:
describe command('ls -al /') do
its('stdout') { should match /bin/ }
its('stderr') { should eq '' }
its('exit_status') { should eq 0 }
end
command('ls -al /').exist? will return false. Existence of command should be checked this way.
describe command('ls') do
it { should exist }
end
Web Reference:
https://github.com/chef/inspec/blob/master/docs/resources.rst#command
inspec> 

View file

@ -0,0 +1,26 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> Name: file
Description:
Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors.
Example:
describe file('path') do
it { should exist }
it { should be_file }
it { should be_readable }
it { should be_writable }
it { should be_owned_by 'root' }
its('mode') { should cmp '0644' }
end
Web Reference:
https://github.com/chef/inspec/blob/master/docs/resources.rst#file
inspec> 

View file

@ -0,0 +1,23 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> 
Available commands:
`[resource]` - run resource on target machine
`help resources` - show all available resources that can be used as commands
`help [resource]` - information about a specific resource
`exit` - exit the InSpec shell
You can use resources in this environment to test the target machine. For example:
command('uname -a').stdout
file('/proc/cpuinfo').content => "value",
You are currently running on:
OS platform: mac_os_x
OS family: darwin
OS release: 10.11.6
inspec> 

View file

@ -0,0 +1,27 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> Name: os
Description:
Use the os InSpec audit resource to test the platform on which the system is running.
Example:
describe os.family do
it { should eq 'redhat' }
end
describe os.redhat? do
it { should eq true }
end
describe os.linux? do
it { should eq true }
end
Web Reference:
https://github.com/chef/inspec/blob/master/docs/resources.rst#os
inspec> 

View file

@ -0,0 +1,5 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> apache apache_conf apt ppa audit_policy auditd_conf auditd_rules command bash file bond bridge directory etc_group gem group grub_conf host iis_site inetd_conf interface iptables json kernel_module kernel_parameter linux_kernel_parameter limits_conf login_defs mount mssql_session mysql mysql_conf mysql_session npm ntp_conf oneget os os_env package parse_config parse_config_file passwd pip port postgres postgres_conf postgres_session powershell script processes registry_key windows_registry_key security_policy service systemd_service upstart_service sysv_service bsd_service launchd_service runit_service shadow ssl ssh_config sshd_config sys_info users user vbscript windows_feature xinetd_conf wmi yum yumrepo yaml csv ini
inspec> 

View file

@ -0,0 +1,10 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> => {"protocol"=>["2"],
"syslogfacility"=>["AUTHPRIV"],
"authorizedkeysfile"=>[".ssh/authorized_keys"],
"useprivilegeseparation"=>["sandbox"],
"acceptenv"=>["LANG LC_*"],
"subsystem"=>["sftp\t/usr/libexec/sftp-server"]}
inspec> 

View file

@ -1,20 +1,19 @@
Commands:
inspec archive PATH # archive a profile to tar.gz (default) ...
inspec check PATH # verify all tests at the specified PATH
inspec compliance SUBCOMMAND ... # Chef Compliance commands
inspec detect # detect the target OS
inspec env # Output shell-appropriate completion co...
inspec exec PATHS # run all test files at the specified PATH.
inspec help [COMMAND] # Describe available commands or one spe...
inspec init TEMPLATE ... # Scaffolds a new project
inspec json PATH # read all tests in PATH and generate a ...
inspec shell # open an interactive debugging shell
inspec supermarket SUBCOMMAND ... # Supermarket commands
inspec vendor # Download all dependencies and generate...
inspec version # prints the version of this tool
Options:
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)
Commands:
inspec archive PATH # archive a profile to tar.gz (default) ...
inspec check PATH # verify all tests at the specified PATH
inspec compliance SUBCOMMAND ... # Chef Compliance commands
inspec detect # detect the target OS
inspec env # Output shell-appropriate completion co...
inspec exec PATHS # run all test files at the specified PATH.
inspec help [COMMAND] # Describe available commands or one spe...
inspec init TEMPLATE ... # Scaffolds a new project
inspec json PATH # read all tests in PATH and generate a ...
inspec shell # open an interactive debugging shell
inspec supermarket SUBCOMMAND ... # Supermarket commands
inspec vendor # Download all dependencies and generate...
inspec version # prints the version of this tool
Options:
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)

View file

@ -0,0 +1,5 @@
I, [2016-09-11T18:48:39.514660 #65769] INFO -- : Checking profile in examples/profile
I, [2016-09-11T18:48:39.514820 #65769] INFO -- : Metadata OK.
I, [2016-09-11T18:48:39.532230 #65769] INFO -- : Found 4 controls.
I, [2016-09-11T18:48:39.532272 #65769] INFO -- : Control definitions OK.
I, [2016-09-11T18:48:39.532442 #65769] INFO -- : Archive /Users/vjeffrey/code/compliance/inspec/profile.tar.gz exists already. Use --overwrite.

View file

@ -0,0 +1,7 @@
Location: examples/profile
Profile: profile
Controls: 4
Timestamp: 2016-09-11T18:48:28-04:00
Valid: true
No errors or warnings

View file

@ -0,0 +1,7 @@
== Operating System Details
Name: mac_os_x
Family: darwin
Release: 10.11.6
Arch: x86_64

View file

@ -0,0 +1 @@
{"name":"mac_os_x","family":"darwin","release":"10.11.6","arch":"x86_64"}

View file

@ -0,0 +1,110 @@
function _inspec() {
local curcontext="$curcontext" state line
typeset -A opt_args
local -a _top_level_commands _compliance_commands _init_commands _supermarket_commands
_top_level_commands=(
"help:Describe\ available\ commands\ or\ one\ specific\ command"
"json:read\ all\ tests\ in\ PATH\ and\ generate\ a\ JSON\ summary"
"check:verify\ all\ tests\ at\ the\ specified\ PATH"
"vendor:Download\ all\ dependencies\ and\ generate\ a\ lockfile"
"archive:archive\ a\ profile\ to\ tar.gz\ \(default\)\ or\ zip"
"exec:run\ all\ test\ files\ at\ the\ specified\ PATH."
"detect:detect\ the\ target\ OS"
"shell:open\ an\ interactive\ debugging\ shell"
"env:Output\ shell-appropriate\ completion\ configuration"
"version:prints\ the\ version\ of\ this\ tool"
"compliance:Chef\ Compliance\ commands"
"init:Scaffolds\ a\ new\ project"
"supermarket:Supermarket\ commands"
)
_compliance_commands=(
"help:Describe\ subcommands\ or\ one\ specific\ subcommand"
"login:Log\ in\ to\ a\ Chef\ Compliance\ SERVER"
"profiles:list\ all\ available\ profiles\ in\ Chef\ Compliance"
"exec:executes\ a\ Chef\ Compliance\ profile"
"upload:uploads\ a\ local\ profile\ to\ Chef\ Compliance"
"version:displays\ the\ version\ of\ the\ Chef\ Compliance\ server"
"logout:user\ logout\ from\ Chef\ Compliance"
)
_init_commands=(
"help:Describe\ subcommands\ or\ one\ specific\ subcommand"
"profile:Create\ a\ new\ profile"
)
_supermarket_commands=(
"help:Describe\ subcommands\ or\ one\ specific\ subcommand"
"profiles:list\ all\ available\ profiles\ in\ Chef\ Supermarket"
"exec:execute\ a\ Supermarket\ profile"
"info:display\ Supermarket\ profile\ details"
)
_arguments '1:::->toplevel' && return 0
_arguments '2:::->subcommand' && return 0
_arguments '3:::->subsubcommand' && return 0
#
# Are you thinking? "Jeez, whoever wrote this really doesn't get
# zsh's completion system?" If so, you are correct. However, I
# have goodnews! Pull requests are accepted!
#
case $state in
toplevel)
_describe -t commands "InSpec subcommands" _top_level_commands
;;
subcommand)
case "$words[2]" in
archive|check|exec|json)
_alternative 'files:filenames:_files'
;;
help)
_describe -t commands "InSpec subcommands" _top_level_commands
;;
compliance)
_describe -t compliance_commands "InSpec compliance subcommands" _compliance_commands
;;
init)
_describe -t init_commands "InSpec init subcommands" _init_commands
;;
supermarket)
_describe -t supermarket_commands "InSpec supermarket subcommands" _supermarket_commands
;;
esac
;;
subsubcommand)
case "$words[2]-$words[3]" in
compliance-upload)
_alternative 'files:filenames:_files'
;;
compliance-help)
_describe -t compliance_commands "InSpec compliance subcommands" _compliance_commands
;;
init-help)
_describe -t init_commands "InSpec init subcommands" _init_commands
;;
supermarket-help)
_describe -t supermarket_commands "InSpec supermarket subcommands" _supermarket_commands
;;
esac
esac
}
compdef _inspec inspec
#
# The shell zsh was auto-detected. If this is incorrect, please
# specify a shell explicitly by running:
#
# inspec env SHELLNAME
#
# Currently supported shells are: bash, zsh
#
# To use this, eval it in your shell
#
# eval "$(inspec env zsh)"
#
#

View file

@ -1,10 +0,0 @@
Target: local://
 ✔ tmp-1.0: Create /tmp directory
 File /tmp should be directory
File /tmp
 ✔ should be directory
Summary: 2 successful, 0 failures, 0 skipped

View file

@ -0,0 +1,16 @@
 ○ gordon-1.0: Verify the version number of Gordon (1 skipped)
 ○ Can't find file "/tmp/gordon/config.yaml"
 ✔ File content should match nil
 ✔ ssh-1: Allow only SSH Protocol 2
 ✔ File /bin/sh should be owned by "root"
File /tmp
 ✔ should be directory
Profile: InSpec example inheritance (inheritance)
Version: 1.0.0
Target: local://
Summary: 3 successful, 0 failures, 1 skipped

View file

@ -0,0 +1,17 @@
Profile: InSpec Example Profile (profile)
Version: 1.0.0
Target: local://
 ✔ tmp-1.0: Create /tmp directory
 ✔ File /tmp should be directory
 ○ gordon-1.0: Verify the version number of Gordon (1 skipped)
 ○ Can't find file "/tmp/gordon/config.yaml"
 ✔ File content should match nil
 ✔ ssh-1: Allow only SSH Protocol 2
 ✔ File /bin/sh should be owned by "root"
File /tmp
 ✔ should be directory
Summary: 4 successful, 0 failures, 1 skipped

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,18 @@
Profile: InSpec Profile (failures)
Version: 0.1.0
Target: local://
 ✖ tmp-1.0: Create /tmp directory (1 failed)
 ✖ expected `File /tmp.directory?` to return false, got true
 ✔ File /tmp should be directory
File /tmp
 ✔ should be directory
 ✖ undefined method `should_nota' for #<RSpec::ExampleGroups::FileTmp_2:0x007fd2fc4f8e50>
File /tmp
 ✖ should not be directory
expected `File /tmp.directory?` to return false, got true
 ✔ should be directory
Summary: 3 successful, 3 failures, 0 skipped

View file

@ -0,0 +1,19 @@
Commands:
inspec archive PATH # archive a profile to tar.gz (default) ...
inspec check PATH # verify all tests at the specified PATH
inspec compliance SUBCOMMAND ... # Chef Compliance commands
inspec detect # detect the target OS
inspec env # Output shell-appropriate completion co...
inspec exec PATHS # run all test files at the specified PATH.
inspec help [COMMAND] # Describe available commands or one spe...
inspec init TEMPLATE ... # Scaffolds a new project
inspec json PATH # read all tests in PATH and generate a ...
inspec shell # open an interactive debugging shell
inspec supermarket SUBCOMMAND ... # Supermarket commands
inspec vendor # Download all dependencies and generate...
inspec version # prints the version of this tool
Options:
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)

View file

@ -0,0 +1,26 @@
Usage:
inspec detect
Options:
t, [--target=TARGET] # Simple targeting option using URIs, e.g. ssh://user:pass@host:port
b, [--backend=BACKEND] # Choose a backend: local, ssh, winrm, docker.
[--host=HOST] # Specify a remote host which is tested.
p, [--port=N] # Specify the login port for a remote scan.
[--user=USER] # The login user for a remote scan.
[--password=PASSWORD] # Login password for a remote scan, if required.
i, [--key-files=one two three] # Login key or certificate file for a remote scan.
[--path=PATH] # Login path to use when connecting to the target (WinRM).
[--sudo], [--no-sudo] # Run scans with sudo. Only activates on Unix and non-root user.
[--sudo-password=SUDO_PASSWORD] # Specify a sudo password, if it is required.
[--sudo-options=SUDO_OPTIONS] # Additional sudo options for a remote scan.
[--sudo-command=SUDO_COMMAND] # Alternate command for sudo.
[--ssl], [--no-ssl] # Use SSL for transport layer encryption (WinRM).
[--self-signed], [--no-self-signed] # Allow remote scans with self-signed certificates (WinRM).
[--json-config=JSON_CONFIG] # Read configuration from JSON file (`-` reads from stdin).
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--format=FORMAT]
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)
detect the target OS

View file

@ -0,0 +1,31 @@
Usage:
inspec exec PATHS
Options:
t, [--target=TARGET] # Simple targeting option using URIs, e.g. ssh://user:pass@host:port
b, [--backend=BACKEND] # Choose a backend: local, ssh, winrm, docker.
[--host=HOST] # Specify a remote host which is tested.
p, [--port=N] # Specify the login port for a remote scan.
[--user=USER] # The login user for a remote scan.
[--password=PASSWORD] # Login password for a remote scan, if required.
i, [--key-files=one two three] # Login key or certificate file for a remote scan.
[--path=PATH] # Login path to use when connecting to the target (WinRM).
[--sudo], [--no-sudo] # Run scans with sudo. Only activates on Unix and non-root user.
[--sudo-password=SUDO_PASSWORD] # Specify a sudo password, if it is required.
[--sudo-options=SUDO_OPTIONS] # Additional sudo options for a remote scan.
[--sudo-command=SUDO_COMMAND] # Alternate command for sudo.
[--ssl], [--no-ssl] # Use SSL for transport layer encryption (WinRM).
[--self-signed], [--no-self-signed] # Allow remote scans with self-signed certificates (WinRM).
[--json-config=JSON_CONFIG] # Read configuration from JSON file (`-` reads from stdin).
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--profiles-path=PROFILES_PATH] # Folder which contains referenced profiles.
[--controls=one two three] # A list of controls to run. Ignore all other tests.
[--format=FORMAT] # Which formatter to use: cli, progress, documentation, json, json-min
[--color], [--no-color] # Use colors in output.
# Default: true
[--attrs=one two three] # Load attributes file (experimental)
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)
run all test files at the specified PATH.

View file

@ -0,0 +1,9 @@
Usage:
inspec version
Options:
l, [--log-level=LOG_LEVEL] # Set the log level: info (default), debug, warn, error
[--log-location=LOG_LOCATION] # Location to send diagnostic log messages to. (default: STDOUT or STDERR)
[--diagnose], [--no-diagnose] # Show diagnostics (versions, configurations)
prints the version of this tool

View file

@ -0,0 +1 @@
{"name":"profile","title":"InSpec Example Profile","maintainer":"Chef Software, Inc.","copyright":"Chef Software, Inc.","copyright_email":"support@chef.io","license":"Apache 2 license","summary":"Demonstrates the use of InSpec Compliance Profile","version":"1.0.0","supports":[{"os-family":"unix"}],"controls":{"tmp-1.0":{"title":"Create /tmp directory","desc":"An optional description...","impact":0.7,"refs":[{"url":"http://...","ref":"Document A-12"}],"tags":{"data":"temp data","security":null},"code":"control \"tmp-1.0\" do # A unique ID for this control\n impact 0.7 # The criticality, if this control fails.\n title \"Create /tmp directory\" # A human-readable title\n desc \"An optional description...\" # Describe why this is needed\n tag data: \"temp data\" # A tag allows you to associate key information\n tag \"security\" # to the test\n ref \"Document A-12\", url: 'http://...' # Additional references\n\n describe file('/tmp') do # The actual test\n it { should be_directory }\n end\nend\n","source_location":{"ref":"examples/profile/controls/example.rb","line":8}},"(generated from example.rb:22 3dea2a8293410b58623a60f2e924ba9a)":{"title":null,"desc":null,"impact":0.5,"refs":[],"tags":{},"code":" rule = rule_class.new(id, profile_id, {}) do\n res = describe(*args, &block)\n end\n","source_location":{"ref":"/Users/vjeffrey/code/compliance/inspec/lib/inspec/control_eval_context.rb","line":87}},"gordon-1.0":{"title":"Verify the version number of Gordon","desc":"An optional description...","impact":0.7,"refs":[{"uri":"http://...","ref":"Gordon Requirements 1.0"}],"tags":{"gordon":null},"code":"control 'gordon-1.0' do\n impact 0.7\n title 'Verify the version number of Gordon'\n desc 'An optional description...'\n tag 'gordon'\n ref 'Gordon Requirements 1.0', uri: 'http://...'\n\n # Test using the custom gordon_config Inspec resource\n # Find the resource content here: ../libraries/\n describe gordon_config do\n it { should exist }\n its('version') { should eq('1.0') }\n its('file_size') { should <= 20 }\n its('comma_count') { should eq 0 }\n end\n\n # Test the version again to showcase variables\n g = gordon_config\n g_path = g.file_path\n g_version = g.version\n describe file(g_path) do\n its('content') { should match g_version }\n end\nend\n","source_location":{"ref":"examples/profile/controls/gordon.rb","line":14}},"ssh-1":{"title":"Allow only SSH Protocol 2","desc":"Only SSH protocol version 2 connections should be permitted. The default setting in /etc/ssh/sshd_config is correct, and can be verified by ensuring that the following line appears: Protocol 2","impact":1.0,"refs":[{"url":"https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf","ref":"NSA-RH6-STIG - Section 3.5.2.1"},{"url":"http://iasecontent.disa.mil/stigs/zip/Jan2016/U_RedHat_6_V1R10_STIG.zip","ref":"DISA-RHEL6-SG - Section 9.2.1"},{"ref":"http://people.redhat.com/swells/scap-security-guide/RHEL/6/output/ssg-centos6-guide-C2S.html"}],"tags":{"production":null,"development":null,"ssh":null,"sshd":null,"openssh-server":null,"cce":"CCE-27072-8","disa":"RHEL-06-000227","nist":"IA-5(1)","cci":"CCI-001436","remediation":"https://supermarket.chef.io/cookbooks/ssh-hardening"},"code":"control 'ssh-1' do\n impact 1.0\n\n title 'Allow only SSH Protocol 2'\n desc 'Only SSH protocol version 2 connections should be permitted.\n The default setting in /etc/ssh/sshd_config is correct, and can be\n verified by ensuring that the following line appears: Protocol 2'\n\n tag 'production','development'\n tag 'ssh','sshd','openssh-server'\n\n tag cce: 'CCE-27072-8'\n tag disa: 'RHEL-06-000227'\n\n tag nist: 'AC-3(10).i'\n tag nist: 'IA-5(1)'\n\n tag cci: 'CCI-000776'\n tag cci: 'CCI-000774'\n tag cci: 'CCI-001436'\n\n tag remediation: 'stig_rhel6/recipes/sshd-config.rb'\n tag remediation: 'https://supermarket.chef.io/cookbooks/ssh-hardening'\n\n ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'\n ref 'DISA-RHEL6-SG - Section 9.2.1', url: 'http://iasecontent.disa.mil/stigs/zip/Jan2016/U_RedHat_6_V1R10_STIG.zip'\n ref 'http://people.redhat.com/swells/scap-security-guide/RHEL/6/output/ssg-centos6-guide-C2S.html'\n\n describe file('/bin/sh') do\n it { should be_owned_by 'root' }\n end\nend\n","source_location":{"ref":"examples/profile/controls/meta.rb","line":3}}},"groups":{"controls/example.rb":{"title":"/tmp profile","controls":["tmp-1.0","(generated from example.rb:22 3dea2a8293410b58623a60f2e924ba9a)"]},"controls/gordon.rb":{"title":"Gordon Config Checks","controls":["gordon-1.0"]},"controls/meta.rb":{"title":"SSH Server Configuration","controls":["ssh-1"]}},"attributes":[]}

View file

@ -0,0 +1,4 @@
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
[?1034hinspec> 

View file

@ -0,0 +1 @@
{:name=>"mac_os_x", :family=>"darwin", :release=>"10.11.6", :arch=>"x86_64"}

View file

@ -1 +1 @@
0.32.0
0.33.2

View file

@ -1 +0,0 @@
README.md

View file

@ -1 +0,0 @@
anonymous-web-user/inspec

View file

@ -1 +0,0 @@
anonymous-web-user/inspec-shell

View file

@ -1,6 +1,6 @@
#terminal-container {
width: 1200px;
height: 500px;
height: 400px;
margin: 0 auto;
padding: 2px;
font-size: 16px;
@ -17,10 +17,14 @@
background-color: #fafafa;
}
/* the black color used by xterm terminal isn't quite black
so we're deep assigning here to make sure that 0 is marked as black */
:host /deep/ .xterm-color-0 {
color: black;
}
/* the blue color that xterm terminal uses doesn't show well
on the black background so we're deep assigning to make 6 a lightskyblu*/
:host /deep/ .xterm-color-6 {
color: lightskyblue;
}

View file

@ -1 +1 @@
<div (keyup)="onKey($event)" id="terminal-container"></div>
<div (keyup)="onKey($event)" (keydown)="handleDelete($event)" id="terminal-container"></div>

View file

@ -8,15 +8,17 @@ declare var Terminal: any;
})
export class XtermTerminalComponent implements OnInit {
@Input() response: string;
@Input() responsesArray: any;
@Input() shell: string;
@Output() command: EventEmitter<string> = new EventEmitter<string>();
// handle up/down arrow functionality
previousCommands: any = [];
last: number;
currentResponse: string;
shellStatus: string;
buffer: string = '';
poppedCommands: any = [];
last: number;
// handle user input
buffer: string = ''; // the buffer is our string of user input
blockCmd: string = ''; // handle describe and control blocks
// xterm variables
terminalContainer: any;
@ -24,24 +26,24 @@ export class XtermTerminalComponent implements OnInit {
optionElements: any;
cols: string;
rows: string;
shellprompt: string = ' $ ';
ngOnInit() {
ngOnInit() {
// set up Xterm terminal (https://github.com/sourcelair/xterm.js)
this.terminalContainer = document.getElementById('terminal-container');
this.cols = '70';
this.rows = '70';
this.createTerminal();
}
}
// watch for changes on the value of response and call printResponse
ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
if (changes['response'] && this.term) {
this.currentResponse = changes['response'].currentValue;
this.term.writeln(this.currentResponse);
this.setPrompt();
let currentResponse = changes['response'].currentValue;
this.printResponse(currentResponse);
}
}
// create Xterm terminal (https://github.com/sourcelair/xterm.js)
createTerminal() {
while (this.terminalContainer.children.length) {
this.terminalContainer.removeChild(this.terminalContainer.children[0]);
@ -62,6 +64,7 @@ export class XtermTerminalComponent implements OnInit {
this.runFakeTerminal()
}
// more Xterm terminal stuff. we're faking it. faking it can be a good thing ;)
runFakeTerminal() {
if (this.term._initialized) {
return;
@ -70,85 +73,155 @@ export class XtermTerminalComponent implements OnInit {
this.setPrompt();
}
setPrompt() {
this.buffer = '';
if (this.shell === 'inspec-shell') {
this.term.write(" " + '\r\ninspec> ');
// if the response matches the special message we send when the user
// has entered 'next' or 'prev' (to navigate through the demo)
// then no need to print the response, just set the prompt. otherwise,
// print response and set prompt
printResponse(response) {
if (response.match(/.30mnext|.30mprev/)) {
this.deleteCharacters();
if (this.term.x < 3) {
// this check prevents us from printing a second prompt on the line
// when the arrow in the nav is used to move forward
this.setPrompt();
}
} else {
this.term.write(this.shellprompt);
this.term.writeln(response);
this.setPrompt();
}
}
// the value of shell is taken as an input. the default
// shellprompt is displayed unless shell is set to 'inspec-shell'
setPrompt() {
this.buffer = '';
if (this.shell === 'inspec-shell') {
if (this.blockCmd != '') {
this.term.write(' inspec>*'); // green inspec shell prompt with * to denote multi-line command
} else {
this.term.write(' inspec> '); // green inspec shell prompt
}
} else {
this.term.write(' $ '); // blue regular shell prompt
}
}
// delete everything on the line
deleteCharacters() {
// don't delete the prompt
let letters = this.term.x - 3;
for (var i = 0; i < letters; i++) {
this.term.write('\b \b');
}
}
// keydown calls handleDelete to check if the user is holding down the backpace key
// TODO: make this work! the backspace event isn't coming in for some reason :(
handleDelete(ev) {
if (ev.keyCode == 8) {
this.deleteCharacters();
}
}
// handle describe and control blocks. if the command entered matches the
// syntax we would generally expect in a control/describe block, then we
// wait to have the whole string command (as marked by 'end' for a simple describe
// block and end end for a control block) and emit that
handleBlockCommand(buffer) {
this.blockCmd += buffer + '';
if (this.blockCmd.match(/^control/)) {
if (this.blockCmd.match(/end.*end.*/)) {
this.command.emit(this.blockCmd);
this.blockCmd = '';
} else {
this.setPrompt();
}
} else {
if (buffer.match(/^end$/)) {
this.command.emit(this.blockCmd);
this.blockCmd = '';
} else {
this.setPrompt();
}
}
}
// onKey will check if the character is printable (on keyup) and add it to the buffer. if the enter key is hit
// the value of the buffer is emitted as 'command'. onKey also supports proper backspace handling and
// the ability to up-arrow through previous commands/down arrow back through them.
onKey(ev) {
var shell = null
// determine if the character is a printable one
var printable = ['Alt', 'Control', 'Meta', 'Shift', 'CapsLock', 'Tab', 'Escape', 'ArrowLeft', 'ArrowRight'].indexOf(ev.key) == -1
// on enter, save command to array and send current value of buffer
// to parent component (app). if the command is the same as the previous command
// entered, we just diplay the currentResponse. the reason this is being done here and
// not in the app component is because the ngOnChanges that tracks the value of the
// emitted event won't recognize that there has been a change if it is the same.
// to parent component (app)
if (ev.keyCode == 13) {
this.previousCommands.push(this.buffer);
this.term.write('\r\n');
if (this.previousCommands.length > 1) {
this.last = this.previousCommands.length - 2
}
if (this.buffer === this.previousCommands[this.last]) {
// if the command is next or last, we still want to emit
// the value, since the parent component is responsible
// for interpreting that value and displaying the correct instructions
if (this.buffer.match(/^next\s*/) || this.buffer.match(/^prev\s*/)) {
this.command.emit(this.buffer);
} else {
this.term.writeln(this.currentResponse);
this.setPrompt();
if ((this.buffer === 'clear') || (this.buffer === 'clr')) {
this.createTerminal();
} else {
this.previousCommands.push(this.buffer);
this.term.write('\r\n');
if (this.shell === 'inspec-shell') {
// if the command entered matches any of the typical describe and
// control blocks, then we call handleBlockCommand to not emit the
// value until we have the whole multi-line command
if (this.buffer.match(/^describe.*|^it.*|^end$|^impact.*|^title.*|^control.*/)) {
this.handleBlockCommand(this.buffer);
}
} else {
this.command.emit(this.buffer);
}
else {
this.command.emit(this.buffer);
}
}
// on backspace, pop characters from buffer
else if (ev.keyCode == 8) {
if (this.term.x > 2) {
this.buffer = this.buffer.substr(0, this.buffer.length-1);
this.term.write('\b \b');
// if inspec shell is being used, this needs to be set to 9 to account for the extra letters
if (this.shell === 'inspec-shell') {
if (this.term.x > 9) {
this.buffer = this.buffer.substr(0, this.buffer.length-1);
this.term.write('\b \b');
}
} else {
// setting the value here to 3 ensures that we don't delete the promp '$' or the space after it
if (this.term.x > 3) {
this.buffer = this.buffer.substr(0, this.buffer.length-1);
this.term.write('\b \b');
}
}
}
// on up arrow, delete anything on line and print previous command
// on up arrow, delete anything on line, print previous command
// and push last to poppedCommands
else if (ev.keyCode === 38) {
let last;
this.buffer = '';
if (this.previousCommands.length > 0) {
last = this.previousCommands.pop();
this.poppedCommands.push(last);
} else {
last = '';
}
let letters = this.term.x - 3;
for (var i = 0; i < letters; i++) {
this.term.write('\b \b');
}
this.deleteCharacters();
this.buffer = last;
this.term.write(last);
}
// on down arrow, delete anything on line and print from popped command
// on down arrow, delete anything on line, print last item from poppedCommands
// and push previous to previousCommands
else if (ev.keyCode === 40) {
let previous;
this.buffer = '';
if (this.poppedCommands.length > 0) {
previous = this.poppedCommands.pop();
this.previousCommands.push(previous);
} else {
previous = '';
}
let letters = this.term.x - 3;
for (var i = 0; i < letters; i++) {
this.term.write('\b \b');
}
this.deleteCharacters();
this.buffer = previous;
this.term.write(previous);
}
// write each character on prompt line
// if the character is printable and none of the event key codes from above were matched
// then we write the character on the prompt line and add the character to the buffer
else if (printable) {
this.term.write(ev.key);
this.buffer += ev.key;

View file

@ -0,0 +1 @@
[[{"inspec":"inspec.txt"}],[{"inspec help":"inspec_help.txt"}],[{"inspec help version":"inspec_help_version.txt"}],[{"inspec help detect":"inspec_help_detect.txt"}],[{"inspec help exec":"inspec_help_exec.txt"}],[{"inspec check examples/profile":"inspec_check_examples_profile.txt"}],[{"inspec exec examples/profile":"inspec_exec_examples_profile.txt"}],[{"inspec help exec":"inspec_help_exec.txt"}],[{"inspec detect":"inspec_detect.txt"}],[{"inspec shell -c 'os.params'":"inspec_shell_c_os_params_.txt"}],[{"inspec shell -c 'sshd_config.Protocol'":"inspec_shell_c_sshd_config_Protocol_.txt"}],[{"inspec shell":"inspec_shell.txt"}],[{"inspec version":"inspec_version.txt"}],[{"inspec detect --format json":"inspec_detect_format_json.txt"}],[{"inspec exec examples/profile --format json":"inspec_exec_examples_profile_format_json.txt"}],[{"inspec exec examples/profile --format json | jq":"inspec_exec_examples_profile_format_json_jq.txt"}],[{"inspec json examples/profile":"inspec_json_examples_profile.txt"}],[{"inspec archive examples/profile":"inspec_archive_examples_profile.txt"}],[{"inspec env":"inspec_env.txt"}],[{"inspec exec examples/inheritance":"inspec_exec_examples_inheritance.txt"}],[{"inspec exec test/unit/mock/profiles/failures":"inspec_exec_test_unit_mock_profiles_failures.txt"}],[{"echo help | inspec shell":"echo_help_inspec_shell.txt"}],[{"echo help\\ resources | inspec shell":"echo_help_resources_inspec_shell.txt"}],[{"echo help\\ file | inspec shell":"echo_help_file_inspec_shell.txt"}],[{"echo help\\ command | inspec shell":"echo_help_command_inspec_shell.txt"}],[{"echo help\\ os | inspec shell":"echo_help_os_inspec_shell.txt"}],[{"echo command\\(\\'uname\\ -a\\'\\).stdout | inspec shell":"echo_command_uname_a_stdout_inspec_shell.txt"}],[{"echo file\\(\\'/proc/cpuinfo\\'\\).owner | inspec shell":"echo_file_proc_cpuinfo_owner_inspec_shell.txt"}],[{"echo sshd_config.params | inspec shell":"echo_sshd_config_params_inspec_shell.txt"}],[{"echo describe\\ file\\(\\'/root\\'\\)\\ do'\n'\\ \\ it\\ \\{\\ should\\ exist\\ \\}'\n'\\ \\ its\\(\\'mode\\'\\)\\ \\{\\ should\\ cmp\\ \\'0750\\'\\}'\n'end | inspec shell":"echo_describe_file_root_do_it_should_exist_its_mode_should_cmp_0750_end_inspec_shell.txt"}],[{"echo control\\ \\\"id\\\"\\ do'\n'\\ \\ title\\ \\\"Check\\ permissions\\ on\\ /root\\!\\\"'\n'\\ \\ impact\\ 0.5'\n'\\ \\ describe\\ file\\(\\'/root\\'\\)\\ do'\n'\\ \\ \\ \\ its\\(\\'mode\\'\\)\\ \\{\\ should\\ cmp\\ \\'0750\\'\\}'\n'\\ \\ end'\n'end | inspec shell":"echo_control_id_do_title_Check_permissions_on_root_impact_0_5_describe_file_root_do_its_mode_should_cmp_0750_end_end_inspec_shell.txt"}]]

10
www/tutorial/commands.yml Normal file
View file

@ -0,0 +1,10 @@
commands:
- inspec version
- inspec detect --format json
- inspec exec examples/profile --format json
- inspec exec examples/profile --format json | jq
- inspec json examples/profile
- inspec archive examples/profile
- inspec env
- inspec exec examples/inheritance
- inspec exec test/unit/mock/profiles/failures

View file

@ -0,0 +1,32 @@
module.exports = {
entry: "./app/main.ts",
output: {
path: __dirname,
filename: "./dist/bundle.js",
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
},
module: {
loaders: [
// All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'.
{
test: /\.tsx?$/, loader: "ts-loader"
},
{
test: /\.css$/, loader: 'style!css',
}
],
preLoaders: [
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader" }
]
},
};

View file

@ -0,0 +1 @@
["inspec version","inspec detect --format json","inspec exec examples/profile --format json","inspec exec examples/profile --format json | jq","inspec json examples/profile","inspec archive examples/profile","inspec env","inspec exec examples/inheritance","inspec exec test/unit/mock/profiles/failures"]

View file

@ -7,6 +7,7 @@
<link rel="stylesheet" href="node_modules/xterm/src/xterm.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<!-- 1. Load libraries -->
<script src="node_modules/shellwords/src/shellwords.coffee"></script>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

View file

@ -23,6 +23,7 @@
"core-js": "^2.4.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"shellwords": "^0.1.0",
"systemjs": "0.19.27",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.15.1",

View file

@ -2,18 +2,17 @@
demos:
- demo: 0:intro
desc: |
Welcome to the interactive InSpec demo. You will learn how to use the commandline and shell and get an introduction to all aspects of the language.
Welcome to the interactive InSpec demo. You will learn how to use the command line and shell and get an introduction to all aspects of the language.
To navigate this demo, type `next` to move forward and `prev` to move back.
Use `clear` to clear the terminal screen.
- demo: 1:inspec-help
desc: |
InSpec is called via
```
inspec
```
Try it out!
You will see the help menu. You can also view it with
Try it out! You will see the help menu. You can also view it with:
```
inspec help
```
@ -31,31 +30,31 @@ demos:
The easiest subcommand is `inspec version`. It tells you which version of InSpec is running.
- demo: 1:inspec-check
desc: |
The most frequent use of InSpec is to execute profiles. You can find the `example/profile` in the InSpec repository. Before executing it for the first time, let's verify if it is valid profile
The most frequent use of InSpec is to execute profiles. You can find the `examples/profile` in the InSpec repository. Before executing it for the first time, let's verify if it is valid profile
```
inspec check example/profile
inspec check examples/profile
```
This command is not only used for syntax testing and linting, but can also provide information on valid profiles including its version and control overview.
- demo: 1:inspec-exec
desc: |
Let's try testing some profiles! To run the profile and test the local machine, type:
```
inspec exec example/profile
inspec exec examples/profile
```
The result is shown in the report.
- demo: 1:inspec-exec-ssh
desc: |
InSpec can also test your remote machines! Let's assume there is node `host.node` registered with SSH configured for user `bob` with a keyfile in the current directory (`bob.rsa`). You can run the same profile against this node via:
```
inspec exec example/profile -t ssh://bob@host.node -i bob.rsa
inspec exec examples/profile -t ssh://bob@host.node -i bob.rsa
```
- demo: 1:inspec-exec-ssh-long
desc: |
The wonderful `-t` option (or `--target`) is a shorthand for specifying all fields separately:
```
inspec exec example/profile -b ssh --host host.node --user bob -i bob.rsa
inspec exec examples/profile -b ssh --host host.node --user bob -i bob.rsa
```
For more options try
For more options try:
```
inspec help exec
```
@ -63,19 +62,19 @@ demos:
desc: |
We can also scan Windows machines. Let's assume `windows.node` is configured with WinRM access for user `alice` with a password `pass`. The command will now read:
```
inspec exec example/profile -t winrm://alice:pass@windows.node
inspec exec examples/profile -t winrm://alice:pass@windows.node
```
- demo: 1:inspec-exec-winrm-ssl
desc: |
The previous example is not quite realistic. Most Windows nodes with WinRM are configured to use SSL. Let's assume the user also has a self-signed certificate. It would now read
```
inspec exec example/profile -t winrm://alice:pass@windows.node --ssl --self-signed
inspec exec examples/profile -t winrm://alice:pass@windows.node --ssl --self-signed
```
- demo: 1:inspec-exec-docker
desc: |
InSpec also supports scanning containers. Let's try it with Docker and pick a container
```
inspec exec example/profile -t docker://abcdef123
inspec exec examples/profile -t docker://abcdef123
```
- demo: 1:inspec-detect
desc: |