<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/interfaces"
	"github.com/FactomProject/factomd/common/primitives"
)

var (
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(*interfaces.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	for i, rcd := range trans.GetRCDs() {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}
<commit_msg>fixed error for address not found in wallet<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/interfaces"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/goleveldb/leveldb"
)

var (
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(*interfaces.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err == leveldb.ErrNotFound {
		return errors.New("No such address in the wallet")
	} else if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	for i, rcd := range trans.GetRCDs() {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/goleveldb/leveldb"
)

var (
	ErrFeeTooHigh    = errors.New("wallet: Overpaying Fee")
	ErrFeeTooLow     = errors.New("wallet: Insufficient Fee")
	ErrNoSuchAddress = errors.New("wallet: No such address")
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXNoInputs    = errors.New("wallet: Transaction has no inputs")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(primitives.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err == leveldb.ErrNotFound {
		return ErrNoSuchAddress
	} else if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if err := checkFee(trans); err != nil {
		return err
	}

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	rcds := trans.GetRCDs()
	if len(rcds) == 0 {
		return ErrTXNoInputs
	}
	for i, rcd := range rcds {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}

func checkFee(t *factoid.Transaction) error {
	ins, err := t.TotalInputs()
	if err != nil {
		return err
	}
	outs, err := t.TotalOutputs()
	if err != nil {
		return err
	}
	ecs, err := t.TotalECs()
	if err != nil {
		return err
	}

	// fee is the fee that will be paid
	fee := int64(ins) - int64(outs) - int64(ecs)

	if fee <= 0 {
		return ErrFeeTooLow
	}

	rate, err := factom.GetRate()
	if err != nil {
		return err
	}

	// cfee is the fee calculated for the transaction
	var cfee int64
	if c, err := t.CalculateFee(rate); err != nil {
		return err
	} else if c == 0 {
		return errors.New("wallet: Could not calculate fee")
	} else {
		cfee = int64(c)
	}

	// fee is too low
	if fee < cfee {
		return ErrFeeTooLow
	}

	// fee is too high (over 10x cfee)
	if fee >= cfee*10 {
		return ErrFeeTooHigh
	}

	return nil
}
<commit_msg>replace instead of combine outputs to the same address<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/goleveldb/leveldb"
)

var (
	ErrFeeTooHigh    = errors.New("wallet: Overpaying Fee")
	ErrFeeTooLow     = errors.New("wallet: Insufficient Fee")
	ErrNoSuchAddress = errors.New("wallet: No such address")
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXNoInputs    = errors.New("wallet: Transaction has no inputs")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(primitives.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err == leveldb.ErrNotFound {
		return ErrNoSuchAddress
	} else if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	// First look if this is really an update
	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(amount)
			return nil
		}
	}

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	// First look if this is really an update
	for _, output := range trans.GetECOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(amount)
			return nil
		}
	}

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if err := checkFee(trans); err != nil {
		return err
	}

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	rcds := trans.GetRCDs()
	if len(rcds) == 0 {
		return ErrTXNoInputs
	}
	for i, rcd := range rcds {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}

func checkFee(t *factoid.Transaction) error {
	ins, err := t.TotalInputs()
	if err != nil {
		return err
	}
	outs, err := t.TotalOutputs()
	if err != nil {
		return err
	}
	ecs, err := t.TotalECs()
	if err != nil {
		return err
	}

	// fee is the fee that will be paid
	fee := int64(ins) - int64(outs) - int64(ecs)

	if fee <= 0 {
		return ErrFeeTooLow
	}

	rate, err := factom.GetRate()
	if err != nil {
		return err
	}

	// cfee is the fee calculated for the transaction
	var cfee int64
	if c, err := t.CalculateFee(rate); err != nil {
		return err
	} else if c == 0 {
		return errors.New("wallet: Could not calculate fee")
	} else {
		cfee = int64(c)
	}

	// fee is too low
	if fee < cfee {
		return ErrFeeTooLow
	}

	// fee is too high (over 10x cfee)
	if fee >= cfee*10 {
		return ErrFeeTooHigh
	}

	return nil
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/bootstrap"
)

func init() {
	Register("bootstrap", runBootstrap, `
usage: flynn-host bootstrap [--min-hosts=<min>] [--json] [<manifest>]

Options:
  -n, --min-hosts=<min>  minimum number of hosts required to be online [default: 1]
  --json                 format log output as json

Bootstrap layer 1 using the provided manifest`)
}

func readBootstrapManifest(name string) ([]byte, error) {
	if name == "" || name == "-" {
		return ioutil.ReadAll(os.Stdin)
	}
	return ioutil.ReadFile(name)
}

var manifest []byte

func runBootstrap(args *docopt.Args) {
	log.SetFlags(log.Lmicroseconds)
	logf := textLogger
	if args.Bool["--json"] {
		logf = jsonLogger
	}

	var err error
	manifest, err = readBootstrapManifest(args.String["<manifest>"])
	if err != nil {
		log.Fatalln("Error reading manifest:", err)
	}

	ch := make(chan *bootstrap.StepInfo)
	done := make(chan struct{})
	go func() {
		for si := range ch {
			logf(si)
		}
		close(done)
	}()

	minHosts, _ := strconv.Atoi(args.String["<min>"])
	err = bootstrap.Run(manifest, ch, minHosts)
	<-done
	if err != nil {
		os.Exit(1)
	}
}

func highlightBytePosition(manifest []byte, pos int64) (line, col int, highlight string) {
	// This function a modified version of a function in Camlistore written by Brad Fitzpatrick
	// https://github.com/bradfitz/camlistore/blob/830c6966a11ddb7834a05b6106b2530284a4d036/pkg/errorutil/highlight.go
	line = 1
	var lastLine string
	var currLine bytes.Buffer
	for i := int64(0); i < pos; i++ {
		b := manifest[i]
		if b == '\n' {
			lastLine = currLine.String()
			currLine.Reset()
			line++
			col = 1
		} else {
			col++
			currLine.WriteByte(b)
		}
	}
	if line > 1 {
		highlight += fmt.Sprintf("%5d: %s\n", line-1, lastLine)
	}
	highlight += fmt.Sprintf("%5d: %s\n", line, currLine.String())
	highlight += fmt.Sprintf("%s^\n", strings.Repeat(" ", col+5))
	return
}

func textLogger(si *bootstrap.StepInfo) {
	switch si.State {
	case "start":
		log.Printf("%s %s", si.Action, si.ID)
	case "done":
		if s, ok := si.StepData.(fmt.Stringer); ok {
			log.Printf("%s %s %s", si.Action, si.ID, s)
		}
	case "error":
		if serr, ok := si.Err.(*json.SyntaxError); ok {
			line, col, highlight := highlightBytePosition(manifest, serr.Offset)
			fmt.Printf("Error parsing JSON: %s\nAt line %d, column %d (offset %d):\n%s", si.Err, line, col, serr.Offset, highlight)
			return
		}
		log.Printf("%s %s error: %s", si.Action, si.ID, si.Error)
	}
}

func jsonLogger(si *bootstrap.StepInfo) {
	json.NewEncoder(os.Stdout).Encode(si)
}
<commit_msg>host/cli: Fix bootstrap min-hosts argument<commit_after>package cli

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/bootstrap"
)

func init() {
	Register("bootstrap", runBootstrap, `
usage: flynn-host bootstrap [--min-hosts=<min>] [--json] [<manifest>]

Options:
  -n, --min-hosts=<min>  minimum number of hosts required to be online [default: 1]
  --json                 format log output as json

Bootstrap layer 1 using the provided manifest`)
}

func readBootstrapManifest(name string) ([]byte, error) {
	if name == "" || name == "-" {
		return ioutil.ReadAll(os.Stdin)
	}
	return ioutil.ReadFile(name)
}

var manifest []byte

func runBootstrap(args *docopt.Args) {
	log.SetFlags(log.Lmicroseconds)
	logf := textLogger
	if args.Bool["--json"] {
		logf = jsonLogger
	}

	var err error
	manifest, err = readBootstrapManifest(args.String["<manifest>"])
	if err != nil {
		log.Fatalln("Error reading manifest:", err)
	}

	ch := make(chan *bootstrap.StepInfo)
	done := make(chan struct{})
	go func() {
		for si := range ch {
			logf(si)
		}
		close(done)
	}()

	minHosts, _ := strconv.Atoi(args.String["--min-hosts"])
	err = bootstrap.Run(manifest, ch, minHosts)
	<-done
	if err != nil {
		os.Exit(1)
	}
}

func highlightBytePosition(manifest []byte, pos int64) (line, col int, highlight string) {
	// This function a modified version of a function in Camlistore written by Brad Fitzpatrick
	// https://github.com/bradfitz/camlistore/blob/830c6966a11ddb7834a05b6106b2530284a4d036/pkg/errorutil/highlight.go
	line = 1
	var lastLine string
	var currLine bytes.Buffer
	for i := int64(0); i < pos; i++ {
		b := manifest[i]
		if b == '\n' {
			lastLine = currLine.String()
			currLine.Reset()
			line++
			col = 1
		} else {
			col++
			currLine.WriteByte(b)
		}
	}
	if line > 1 {
		highlight += fmt.Sprintf("%5d: %s\n", line-1, lastLine)
	}
	highlight += fmt.Sprintf("%5d: %s\n", line, currLine.String())
	highlight += fmt.Sprintf("%s^\n", strings.Repeat(" ", col+5))
	return
}

func textLogger(si *bootstrap.StepInfo) {
	switch si.State {
	case "start":
		log.Printf("%s %s", si.Action, si.ID)
	case "done":
		if s, ok := si.StepData.(fmt.Stringer); ok {
			log.Printf("%s %s %s", si.Action, si.ID, s)
		}
	case "error":
		if serr, ok := si.Err.(*json.SyntaxError); ok {
			line, col, highlight := highlightBytePosition(manifest, serr.Offset)
			fmt.Printf("Error parsing JSON: %s\nAt line %d, column %d (offset %d):\n%s", si.Err, line, col, serr.Offset, highlight)
			return
		}
		log.Printf("%s %s error: %s", si.Action, si.ID, si.Error)
	}
}

func jsonLogger(si *bootstrap.StepInfo) {
	json.NewEncoder(os.Stdout).Encode(si)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The math package provides basic constants and mathematical functions.
package math

// Mathematical constants.
// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
const (
	E	= 2.71828182845904523536028747135266249775724709369995957496696763;  // A001113
	Pi	= 3.14159265358979323846264338327950288419716939937510582097494459;  // A000796
	Phi	= 1.61803398874989484820458683436563811772030917980576286213544862;  // A001622

	Sqrt2	= 1.41421356237309504880168872420969807856967187537694807317667974;  // A002193
	SqrtE	= 1.64872127070012814684865078781416357165377610071014801157507931;  // A019774
	SqrtPi	= 1.77245385090551602729816748334114518279754945612238712821380779;  // A002161
	SqrtPhi	= 1.27201964951406896425242246173749149171560804184009624861664038;  // A139339

	Ln2	= 0.693147180559945309417232121458176568075500134360255254120680009; // A002162
	Log2E	= 1/Ln2;
	Ln10	= 2.30258509299404568401799145468436420760110148862877297603332790;  // A002392
	Log10E	= 1/Ln10;

	MaxFloat32	= 3.40282346638528860e+38;
	MinFloat32	= 1.40129846432481707e-45;
	MaxFloat64	= 1.7976931348623157e+308;
	MinFloat64	= 5.0e-324;
)

// BUG(rsc): The manual should define the special cases for all of these functions.
<commit_msg>constants for integer limits<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The math package provides basic constants and mathematical functions.
package math

// Mathematical constants.
// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
const (
	E	= 2.71828182845904523536028747135266249775724709369995957496696763;  // A001113
	Pi	= 3.14159265358979323846264338327950288419716939937510582097494459;  // A000796
	Phi	= 1.61803398874989484820458683436563811772030917980576286213544862;  // A001622

	Sqrt2	= 1.41421356237309504880168872420969807856967187537694807317667974;  // A002193
	SqrtE	= 1.64872127070012814684865078781416357165377610071014801157507931;  // A019774
	SqrtPi	= 1.77245385090551602729816748334114518279754945612238712821380779;  // A002161
	SqrtPhi	= 1.27201964951406896425242246173749149171560804184009624861664038;  // A139339

	Ln2	= 0.693147180559945309417232121458176568075500134360255254120680009; // A002162
	Log2E	= 1/Ln2;
	Ln10	= 2.30258509299404568401799145468436420760110148862877297603332790;  // A002392
	Log10E	= 1/Ln10;
)

// Limit values
const (
	MaxFloat32	= 3.40282346638528860e+38;
	MinFloat32	= 1.40129846432481707e-45;
	MaxFloat64	= 1.7976931348623157e+308;
	MinFloat64	= 5.0e-324;

	MaxInt8 = 1<<7 - 1;
	MinInt8 = -1<<7;
	MaxInt16 = 1<<15 - 1;
	MinInt16 = -1<<15;
	MaxInt32 = 1<<31 - 1;
	MinInt32 = -1<<31;
	MaxInt64 = 1<<63 - 1;
	MinInt64 = -1<<63;
	MaxUint8 = 1<<8 - 1;
	MaxUint16 = 1<<16 - 1;
	MaxUint32 = 1<<32 - 1;
	MaxUint64 = 1<<64 - 1;
)

// BUG(rsc): The manual should define the special cases for all of these functions.
<|endoftext|>


<commit_before>package integration

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"encoding/json"

	"github.com/containers/buildah"
	"github.com/containers/image/copy"
	"github.com/containers/image/signature"
	"github.com/containers/image/storage"
	"github.com/containers/image/transports/alltransports"
	"github.com/containers/image/types"
	sstorage "github.com/containers/storage"
	"github.com/containers/storage/pkg/reexec"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pkg/errors"
)

var (
	INTEGRATION_ROOT   string
	STORAGE_OPTIONS    = "--storage-driver vfs"
	ARTIFACT_DIR       = "/tmp/.artifacts"
	CACHE_IMAGES       = []string{"alpine", "busybox", FEDORA_MINIMAL}
	RESTORE_IMAGES     = []string{"alpine", "busybox"}
	ALPINE             = "docker.io/library/alpine:latest"
	BB_GLIBC           = "docker.io/library/busybox:glibc"
	FEDORA_MINIMAL     = "registry.fedoraproject.org/fedora-minimal:latest"
	defaultWaitTimeout = 90
)

// BuildAhSession wraps the gexec.session so we can extend it
type BuildAhSession struct {
	*gexec.Session
}

// BuildAhTest struct for command line options
type BuildAhTest struct {
	BuildAhBinary  string
	RunRoot        string
	StorageOptions string
	ArtifactPath   string
	TempDir        string
	SignaturePath  string
	Root           string
	RegistriesConf string
}

// TestBuildAh ginkgo master function
func TestBuildAh(t *testing.T) {
	if reexec.Init() {
		os.Exit(1)
	}
	RegisterFailHandler(Fail)
	RunSpecs(t, "Buildah Suite")
}

var _ = BeforeSuite(func() {
	//Cache images
	cwd, _ := os.Getwd()
	INTEGRATION_ROOT = filepath.Join(cwd, "../../")
	buildah := BuildahCreate("/tmp")
	buildah.ArtifactPath = ARTIFACT_DIR
	if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
		if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
			fmt.Printf("%q\n", err)
			os.Exit(1)
		}
	}
	for _, image := range CACHE_IMAGES {
		fmt.Printf("Caching %s...\n", image)
		if err := buildah.CreateArtifact(image); err != nil {
			fmt.Printf("%q\n", err)
			os.Exit(1)
		}
	}

})

// CreateTempDirin
func CreateTempDirInTempDir() (string, error) {
	return ioutil.TempDir("", "buildah_test")
}

// BuildahCreate a BuildAhTest instance for the tests
func BuildahCreate(tempDir string) BuildAhTest {
	cwd, _ := os.Getwd()

	buildAhBinary := filepath.Join(cwd, "../../buildah")
	if os.Getenv("BUILDAH_BINARY") != "" {
		buildAhBinary = os.Getenv("BUILDAH_BINARY")
	}
	storageOptions := STORAGE_OPTIONS
	if os.Getenv("STORAGE_OPTIONS") != "" {
		storageOptions = os.Getenv("STORAGE_OPTIONS")
	}

	return BuildAhTest{
		BuildAhBinary:  buildAhBinary,
		RunRoot:        filepath.Join(tempDir, "runroot"),
		Root:           filepath.Join(tempDir, "root"),
		StorageOptions: storageOptions,
		ArtifactPath:   ARTIFACT_DIR,
		TempDir:        tempDir,
		SignaturePath:  "../../tests/policy.json",
		RegistriesConf: "../../registries.conf",
	}
}

//MakeOptions assembles all the buildah main options
func (p *BuildAhTest) MakeOptions() []string {
	return strings.Split(fmt.Sprintf("--root %s --runroot %s --registries-conf %s",
		p.Root, p.RunRoot, p.RegistriesConf), " ")
}

// BuildAh is the exec call to buildah on the filesystem
func (p *BuildAhTest) BuildAh(args []string) *BuildAhSession {
	buildAhOptions := p.MakeOptions()
	buildAhOptions = append(buildAhOptions, strings.Split(p.StorageOptions, " ")...)
	buildAhOptions = append(buildAhOptions, args...)
	fmt.Printf("Running: %s %s\n", p.BuildAhBinary, strings.Join(buildAhOptions, " "))
	command := exec.Command(p.BuildAhBinary, buildAhOptions...)
	session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
	if err != nil {
		Fail(fmt.Sprintf("unable to run buildah command: %s", strings.Join(buildAhOptions, " ")))
	}
	return &BuildAhSession{session}
}

// Cleanup cleans up the temporary store
func (p *BuildAhTest) Cleanup() {
	// Nuke tempdir
	if err := os.RemoveAll(p.TempDir); err != nil {
		fmt.Printf("%q\n", err)
	}
}

// GrepString takes session output and behaves like grep. it returns a bool
// if successful and an array of strings on positive matches
func (s *BuildAhSession) GrepString(term string) (bool, []string) {
	var (
		greps   []string
		matches bool
	)

	for _, line := range strings.Split(s.OutputToString(), "\n") {
		if strings.Contains(line, term) {
			matches = true
			greps = append(greps, line)
		}
	}
	return matches, greps
}

// OutputToString formats session output to string
func (s *BuildAhSession) OutputToString() string {
	fields := strings.Fields(fmt.Sprintf("%s", s.Out.Contents()))
	return strings.Join(fields, " ")
}

// OutputToStringArray returns the output as a []string
// where each array item is a line split by newline
func (s *BuildAhSession) OutputToStringArray() []string {
	output := fmt.Sprintf("%s", s.Out.Contents())
	return strings.Split(output, "\n")
}

// IsJSONOutputValid attempts to unmarshall the session buffer
// and if successful, returns true, else false
func (s *BuildAhSession) IsJSONOutputValid() bool {
	var i interface{}
	if err := json.Unmarshal(s.Out.Contents(), &i); err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

func (s *BuildAhSession) WaitWithDefaultTimeout() {
	s.Wait(defaultWaitTimeout)
}

// SystemExec is used to exec a system command to check its exit code or output
func (p *BuildAhTest) SystemExec(command string, args []string) *BuildAhSession {
	c := exec.Command(command, args...)
	session, err := gexec.Start(c, GinkgoWriter, GinkgoWriter)
	if err != nil {
		Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
	}
	return &BuildAhSession{session}
}

// CreateArtifact creates a cached image in the artifact dir
func (p *BuildAhTest) CreateArtifact(image string) error {
	imageName := fmt.Sprintf("docker://%s", image)
	systemContext := types.SystemContext{
		SignaturePolicyPath: p.SignaturePath,
	}
	policy, err := signature.DefaultPolicy(&systemContext)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	policyContext, err := signature.NewPolicyContext(policy)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	defer func() {
		_ = policyContext.Destroy()
	}()
	options := &copy.Options{}

	importRef, err := alltransports.ParseImageName(imageName)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", image, err)
	}

	imageDir := strings.Replace(image, "/", "_", -1)
	exportTo := filepath.Join("dir:", p.ArtifactPath, imageDir)
	exportRef, err := alltransports.ParseImageName(exportTo)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", exportTo, err)
	}

	return copy.Image(context.Background(), policyContext, exportRef, importRef, options)
}

// RestoreArtifact puts the cached image into our test store
func (p *BuildAhTest) RestoreArtifact(image string) error {
	storeOptions := sstorage.DefaultStoreOptions
	storeOptions.GraphDriverName = "vfs"
	//storeOptions.GraphDriverOptions = storageOptions
	storeOptions.GraphRoot = p.Root
	storeOptions.RunRoot = p.RunRoot
	store, err := sstorage.GetStore(storeOptions)

	options := &copy.Options{}
	if err != nil {
		return errors.Errorf("error opening storage: %v", err)
	}
	defer func() {
		_, _ = store.Shutdown(false)
	}()

	storage.Transport.SetStore(store)
	ref, err := storage.Transport.ParseStoreReference(store, image)
	if err != nil {
		return errors.Errorf("error parsing image name: %v", err)
	}

	imageDir := strings.Replace(image, "/", "_", -1)
	importFrom := fmt.Sprintf("dir:%s", filepath.Join(p.ArtifactPath, imageDir))
	importRef, err := alltransports.ParseImageName(importFrom)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", image, err)
	}
	systemContext := types.SystemContext{
		SignaturePolicyPath: p.SignaturePath,
	}
	policy, err := signature.DefaultPolicy(&systemContext)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	policyContext, err := signature.NewPolicyContext(policy)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	defer func() {
		_ = policyContext.Destroy()
	}()
	err = copy.Image(context.Background(), policyContext, ref, importRef, options)
	if err != nil {
		return errors.Errorf("error importing %s: %v", importFrom, err)
	}
	return nil
}

// RestoreAllArtifacts unpacks all cached images
func (p *BuildAhTest) RestoreAllArtifacts() error {
	for _, image := range RESTORE_IMAGES {
		if err := p.RestoreArtifact(image); err != nil {
			return err
		}
	}
	return nil
}

// StringInSlice determines if a string is in a string slice, returns bool
func StringInSlice(s string, sl []string) bool {
	for _, i := range sl {
		if i == s {
			return true
		}
	}
	return false
}

//LineInOutputStartsWith returns true if a line in a
// session output starts with the supplied string
func (s *BuildAhSession) LineInOuputStartsWith(term string) bool {
	for _, i := range s.OutputToStringArray() {
		if strings.HasPrefix(i, term) {
			return true
		}
	}
	return false
}

//LineInOutputContains returns true if a line in a
// session output starts with the supplied string
func (s *BuildAhSession) LineInOuputContains(term string) bool {
	for _, i := range s.OutputToStringArray() {
		if strings.Contains(i, term) {
			return true
		}
	}
	return false
}

// InspectContainerToJSON takes the session output of an inspect
// container and returns json
func (s *BuildAhSession) InspectImageJSON() buildah.BuilderInfo {
	var i buildah.BuilderInfo
	err := json.Unmarshal(s.Out.Contents(), &i)
	Expect(err).To(BeNil())
	return i
}
<commit_msg>Update calls in e2e to addres 1101<commit_after>package integration

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"encoding/json"

	"github.com/containers/buildah"
	"github.com/containers/image/copy"
	"github.com/containers/image/signature"
	"github.com/containers/image/storage"
	"github.com/containers/image/transports/alltransports"
	"github.com/containers/image/types"
	sstorage "github.com/containers/storage"
	"github.com/containers/storage/pkg/reexec"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pkg/errors"
)

var (
	INTEGRATION_ROOT   string
	STORAGE_OPTIONS    = "--storage-driver vfs"
	ARTIFACT_DIR       = "/tmp/.artifacts"
	CACHE_IMAGES       = []string{"alpine", "busybox", FEDORA_MINIMAL}
	RESTORE_IMAGES     = []string{"alpine", "busybox"}
	ALPINE             = "docker.io/library/alpine:latest"
	BB_GLIBC           = "docker.io/library/busybox:glibc"
	FEDORA_MINIMAL     = "registry.fedoraproject.org/fedora-minimal:latest"
	defaultWaitTimeout = 90
)

// BuildAhSession wraps the gexec.session so we can extend it
type BuildAhSession struct {
	*gexec.Session
}

// BuildAhTest struct for command line options
type BuildAhTest struct {
	BuildAhBinary  string
	RunRoot        string
	StorageOptions string
	ArtifactPath   string
	TempDir        string
	SignaturePath  string
	Root           string
	RegistriesConf string
}

// TestBuildAh ginkgo master function
func TestBuildAh(t *testing.T) {
	if reexec.Init() {
		os.Exit(1)
	}
	RegisterFailHandler(Fail)
	RunSpecs(t, "Buildah Suite")
}

var _ = BeforeSuite(func() {
	//Cache images
	cwd, _ := os.Getwd()
	INTEGRATION_ROOT = filepath.Join(cwd, "../../")
	buildah := BuildahCreate("/tmp")
	buildah.ArtifactPath = ARTIFACT_DIR
	if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
		if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
			fmt.Printf("%q\n", err)
			os.Exit(1)
		}
	}
	for _, image := range CACHE_IMAGES {
		fmt.Printf("Caching %s...\n", image)
		if err := buildah.CreateArtifact(image); err != nil {
			fmt.Printf("%q\n", err)
			os.Exit(1)
		}
	}

})

// CreateTempDirin
func CreateTempDirInTempDir() (string, error) {
	return ioutil.TempDir("", "buildah_test")
}

// BuildahCreate a BuildAhTest instance for the tests
func BuildahCreate(tempDir string) BuildAhTest {
	cwd, _ := os.Getwd()

	buildAhBinary := filepath.Join(cwd, "../../buildah")
	if os.Getenv("BUILDAH_BINARY") != "" {
		buildAhBinary = os.Getenv("BUILDAH_BINARY")
	}
	storageOptions := STORAGE_OPTIONS
	if os.Getenv("STORAGE_OPTIONS") != "" {
		storageOptions = os.Getenv("STORAGE_OPTIONS")
	}

	return BuildAhTest{
		BuildAhBinary:  buildAhBinary,
		RunRoot:        filepath.Join(tempDir, "runroot"),
		Root:           filepath.Join(tempDir, "root"),
		StorageOptions: storageOptions,
		ArtifactPath:   ARTIFACT_DIR,
		TempDir:        tempDir,
		SignaturePath:  "../../tests/policy.json",
		RegistriesConf: "../../registries.conf",
	}
}

//MakeOptions assembles all the buildah main options
func (p *BuildAhTest) MakeOptions() []string {
	return strings.Split(fmt.Sprintf("--root %s --runroot %s --registries-conf %s",
		p.Root, p.RunRoot, p.RegistriesConf), " ")
}

// BuildAh is the exec call to buildah on the filesystem
func (p *BuildAhTest) BuildAh(args []string) *BuildAhSession {
	buildAhOptions := p.MakeOptions()
	buildAhOptions = append(buildAhOptions, strings.Split(p.StorageOptions, " ")...)
	buildAhOptions = append(buildAhOptions, args...)
	fmt.Printf("Running: %s %s\n", p.BuildAhBinary, strings.Join(buildAhOptions, " "))
	command := exec.Command(p.BuildAhBinary, buildAhOptions...)
	session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
	if err != nil {
		Fail(fmt.Sprintf("unable to run buildah command: %s", strings.Join(buildAhOptions, " ")))
	}
	return &BuildAhSession{session}
}

// Cleanup cleans up the temporary store
func (p *BuildAhTest) Cleanup() {
	// Nuke tempdir
	if err := os.RemoveAll(p.TempDir); err != nil {
		fmt.Printf("%q\n", err)
	}
}

// GrepString takes session output and behaves like grep. it returns a bool
// if successful and an array of strings on positive matches
func (s *BuildAhSession) GrepString(term string) (bool, []string) {
	var (
		greps   []string
		matches bool
	)

	for _, line := range strings.Split(s.OutputToString(), "\n") {
		if strings.Contains(line, term) {
			matches = true
			greps = append(greps, line)
		}
	}
	return matches, greps
}

// OutputToString formats session output to string
func (s *BuildAhSession) OutputToString() string {
	fields := strings.Fields(fmt.Sprintf("%s", s.Out.Contents()))
	return strings.Join(fields, " ")
}

// OutputToStringArray returns the output as a []string
// where each array item is a line split by newline
func (s *BuildAhSession) OutputToStringArray() []string {
	output := fmt.Sprintf("%s", s.Out.Contents())
	return strings.Split(output, "\n")
}

// IsJSONOutputValid attempts to unmarshall the session buffer
// and if successful, returns true, else false
func (s *BuildAhSession) IsJSONOutputValid() bool {
	var i interface{}
	if err := json.Unmarshal(s.Out.Contents(), &i); err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

func (s *BuildAhSession) WaitWithDefaultTimeout() {
	s.Wait(defaultWaitTimeout)
}

// SystemExec is used to exec a system command to check its exit code or output
func (p *BuildAhTest) SystemExec(command string, args []string) *BuildAhSession {
	c := exec.Command(command, args...)
	session, err := gexec.Start(c, GinkgoWriter, GinkgoWriter)
	if err != nil {
		Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
	}
	return &BuildAhSession{session}
}

// CreateArtifact creates a cached image in the artifact dir
func (p *BuildAhTest) CreateArtifact(image string) error {
	imageName := fmt.Sprintf("docker://%s", image)
	systemContext := types.SystemContext{
		SignaturePolicyPath: p.SignaturePath,
	}
	policy, err := signature.DefaultPolicy(&systemContext)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	policyContext, err := signature.NewPolicyContext(policy)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	defer func() {
		_ = policyContext.Destroy()
	}()
	options := &copy.Options{}

	importRef, err := alltransports.ParseImageName(imageName)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", image, err)
	}

	imageDir := strings.Replace(image, "/", "_", -1)
	exportTo := filepath.Join("dir:", p.ArtifactPath, imageDir)
	exportRef, err := alltransports.ParseImageName(exportTo)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", exportTo, err)
	}

	_, err = copy.Image(context.Background(), policyContext, exportRef, importRef, options)
	return err
}

// RestoreArtifact puts the cached image into our test store
func (p *BuildAhTest) RestoreArtifact(image string) error {
	storeOptions := sstorage.DefaultStoreOptions
	storeOptions.GraphDriverName = "vfs"
	//storeOptions.GraphDriverOptions = storageOptions
	storeOptions.GraphRoot = p.Root
	storeOptions.RunRoot = p.RunRoot
	store, err := sstorage.GetStore(storeOptions)

	options := &copy.Options{}
	if err != nil {
		return errors.Errorf("error opening storage: %v", err)
	}
	defer func() {
		_, _ = store.Shutdown(false)
	}()

	storage.Transport.SetStore(store)
	ref, err := storage.Transport.ParseStoreReference(store, image)
	if err != nil {
		return errors.Errorf("error parsing image name: %v", err)
	}

	imageDir := strings.Replace(image, "/", "_", -1)
	importFrom := fmt.Sprintf("dir:%s", filepath.Join(p.ArtifactPath, imageDir))
	importRef, err := alltransports.ParseImageName(importFrom)
	if err != nil {
		return errors.Errorf("error parsing image name %v: %v", image, err)
	}
	systemContext := types.SystemContext{
		SignaturePolicyPath: p.SignaturePath,
	}
	policy, err := signature.DefaultPolicy(&systemContext)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	policyContext, err := signature.NewPolicyContext(policy)
	if err != nil {
		return errors.Errorf("error loading signature policy: %v", err)
	}
	defer func() {
		_ = policyContext.Destroy()
	}()
	_, err = copy.Image(context.Background(), policyContext, ref, importRef, options)
	if err != nil {
		return errors.Errorf("error importing %s: %v", importFrom, err)
	}
	return nil
}

// RestoreAllArtifacts unpacks all cached images
func (p *BuildAhTest) RestoreAllArtifacts() error {
	for _, image := range RESTORE_IMAGES {
		if err := p.RestoreArtifact(image); err != nil {
			return err
		}
	}
	return nil
}

// StringInSlice determines if a string is in a string slice, returns bool
func StringInSlice(s string, sl []string) bool {
	for _, i := range sl {
		if i == s {
			return true
		}
	}
	return false
}

//LineInOutputStartsWith returns true if a line in a
// session output starts with the supplied string
func (s *BuildAhSession) LineInOuputStartsWith(term string) bool {
	for _, i := range s.OutputToStringArray() {
		if strings.HasPrefix(i, term) {
			return true
		}
	}
	return false
}

//LineInOutputContains returns true if a line in a
// session output starts with the supplied string
func (s *BuildAhSession) LineInOuputContains(term string) bool {
	for _, i := range s.OutputToStringArray() {
		if strings.Contains(i, term) {
			return true
		}
	}
	return false
}

// InspectContainerToJSON takes the session output of an inspect
// container and returns json
func (s *BuildAhSession) InspectImageJSON() buildah.BuilderInfo {
	var i buildah.BuilderInfo
	err := json.Unmarshal(s.Out.Contents(), &i)
	Expect(err).To(BeNil())
	return i
}
<|endoftext|>


<commit_before>package smoke_tests

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/cloudfoundry-incubator/cf-test-helpers/config"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
)

var (
	configPath = os.Getenv("CONFIG_PATH")
	testConfig = loadTestConfig(configPath)
	wfh        *workflowhelpers.ReproducibleTestSuiteSetup
)

func TestLifecycle(t *testing.T) {
	SynchronizedBeforeSuite(func() []byte {

		wfh = workflowhelpers.NewTestSuiteSetup(&testConfig.Config)
		wfh.Setup()

		return []byte{}
	}, func([]byte) {
	})

	SynchronizedAfterSuite(func() {
	}, func() {
		wfh.Teardown()
	})

	RegisterFailHandler(Fail)
	RunSpecs(t, "Lifecycle Suite")
}

func loadTestConfig(configPath string) TestConfig {
	if configPath == "" {
		panic(fmt.Errorf("Path to config file is empty -- Did you set CONFIG_PATH?"))
	}
	configFile, err := os.Open(configPath)
	if err != nil {
		panic(fmt.Errorf("Could not open config file at %s --  ERROR %s", configPath, err.Error()))
	}

	defer configFile.Close()
	var testConfig TestConfig
	err = json.NewDecoder(configFile).Decode(&testConfig)
	if err != nil {
		panic(fmt.Errorf("Could not decode config json -- ERROR: %s", err.Error()))
	}

	return testConfig
}

type TestConfig struct {
	config.Config

	TestPlans       []TestPlan `json:"plans"`
	ServiceOffering string     `json:"service_offering"`
	AppType         string     `json:"app_type"`
}

type TestPlan struct {
	Name string `json:"name"`
}
<commit_msg>Rename suite spec name<commit_after>package smoke_tests

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/cloudfoundry-incubator/cf-test-helpers/config"
	"github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
)

var (
	configPath = os.Getenv("CONFIG_PATH")
	testConfig = loadTestConfig(configPath)
	wfh        *workflowhelpers.ReproducibleTestSuiteSetup
)

func TestLifecycle(t *testing.T) {
	SynchronizedBeforeSuite(func() []byte {

		wfh = workflowhelpers.NewTestSuiteSetup(&testConfig.Config)
		wfh.Setup()

		return []byte{}
	}, func([]byte) {
	})

	SynchronizedAfterSuite(func() {
	}, func() {
		wfh.Teardown()
	})

	RegisterFailHandler(Fail)
	RunSpecs(t, "Smoke Tests Suite")
}

func loadTestConfig(configPath string) TestConfig {
	if configPath == "" {
		panic(fmt.Errorf("Path to config file is empty -- Did you set CONFIG_PATH?"))
	}
	configFile, err := os.Open(configPath)
	if err != nil {
		panic(fmt.Errorf("Could not open config file at %s --  ERROR %s", configPath, err.Error()))
	}

	defer configFile.Close()
	var testConfig TestConfig
	err = json.NewDecoder(configFile).Decode(&testConfig)
	if err != nil {
		panic(fmt.Errorf("Could not decode config json -- ERROR: %s", err.Error()))
	}

	return testConfig
}

type TestConfig struct {
	config.Config

	TestPlans       []TestPlan `json:"plans"`
	ServiceOffering string     `json:"service_offering"`
	AppType         string     `json:"app_type"`
}

type TestPlan struct {
	Name string `json:"name"`
}
<|endoftext|>


<commit_before>package container // import "github.com/docker/docker/integration/container"

import (
	"bufio"
	"context"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"testing"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/client"
	"github.com/docker/docker/integration/internal/container"
	"github.com/docker/docker/internal/test/daemon"
	"github.com/docker/docker/internal/test/request"
	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
	"gotest.tools/fs"
	"gotest.tools/skip"
)

// testIpcCheckDevExists checks whether a given mount (identified by its
// major:minor pair from /proc/self/mountinfo) exists on the host system.
//
// The format of /proc/self/mountinfo is like:
//
// 29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
//       ^^^^\
//            - this is the minor:major we look for
func testIpcCheckDevExists(mm string) (bool, error) {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return false, err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		fields := strings.Fields(s.Text())
		if len(fields) < 7 {
			continue
		}
		if fields[2] == mm {
			return true, nil
		}
	}

	return false, s.Err()
}

// testIpcNonePrivateShareable is a helper function to test "none",
// "private" and "shareable" modes.
func testIpcNonePrivateShareable(t *testing.T, mode string, mustBeMounted bool, mustBeShared bool) {
	defer setupTest(t)()

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode(mode),
	}
	client := testEnv.APIClient()
	ctx := context.Background()

	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))

	err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// get major:minor pair for /dev/shm from container's /proc/self/mountinfo
	cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo"
	result, err := container.Exec(ctx, client, resp.ID, []string{"sh", "-c", cmd})
	assert.NilError(t, err)
	mm := result.Combined()
	if !mustBeMounted {
		assert.Check(t, is.Equal(mm, ""))
		// no more checks to perform
		return
	}
	assert.Check(t, is.Equal(true, regexp.MustCompile("^[0-9]+:[0-9]+$").MatchString(mm)))

	shared, err := testIpcCheckDevExists(mm)
	assert.NilError(t, err)
	t.Logf("[testIpcPrivateShareable] ipcmode: %v, ipcdev: %v, shared: %v, mustBeShared: %v\n", mode, mm, shared, mustBeShared)
	assert.Check(t, is.Equal(shared, mustBeShared))
}

// TestIpcModeNone checks the container "none" IPC mode
// (--ipc none) works as expected. It makes sure there is no
// /dev/shm mount inside the container.
func TestIpcModeNone(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "none", false, false)
}

// TestAPIIpcModePrivate checks the container private IPC mode
// (--ipc private) works as expected. It gets the minor:major pair
// of /dev/shm mount from the container, and makes sure there is no
// such pair on the host.
func TestIpcModePrivate(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "private", true, false)
}

// TestAPIIpcModeShareable checks the container shareable IPC mode
// (--ipc shareable) works as expected. It gets the minor:major pair
// of /dev/shm mount from the container, and makes sure such pair
// also exists on the host.
func TestIpcModeShareable(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "shareable", true, true)
}

// testIpcContainer is a helper function to test --ipc container:NNN mode in various scenarios
func testIpcContainer(t *testing.T, donorMode string, mustWork bool) {
	t.Helper()

	defer setupTest(t)()

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode(donorMode),
	}
	ctx := context.Background()
	client := testEnv.APIClient()

	// create and start the "donor" container
	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name1 := resp.ID

	err = client.ContainerStart(ctx, name1, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// create and start the second container
	hostCfg.IpcMode = containertypes.IpcMode("container:" + name1)
	resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name2 := resp.ID

	err = client.ContainerStart(ctx, name2, types.ContainerStartOptions{})
	if !mustWork {
		// start should fail with a specific error
		assert.Check(t, is.ErrorContains(err, "non-shareable IPC"))
		// no more checks to perform here
		return
	}

	// start should succeed
	assert.NilError(t, err)

	// check that IPC is shared
	// 1. create a file in the first container
	_, err = container.Exec(ctx, client, name1, []string{"sh", "-c", "printf covfefe > /dev/shm/bar"})
	assert.NilError(t, err)
	// 2. check it's the same file in the second one
	result, err := container.Exec(ctx, client, name2, []string{"cat", "/dev/shm/bar"})
	assert.NilError(t, err)
	out := result.Combined()
	assert.Check(t, is.Equal(true, regexp.MustCompile("^covfefe$").MatchString(out)))
}

// TestAPIIpcModeShareableAndPrivate checks that
// 1) a container created with --ipc container:ID can use IPC of another shareable container.
// 2) a container created with --ipc container:ID can NOT use IPC of another private container.
func TestAPIIpcModeShareableAndContainer(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcContainer(t, "shareable", true)

	testIpcContainer(t, "private", false)
}

/* TestAPIIpcModeHost checks that a container created with --ipc host
 * can use IPC of the host system.
 */
func TestAPIIpcModeHost(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)
	skip.If(t, testEnv.IsUserNamespace)

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode("host"),
	}
	ctx := context.Background()

	client := testEnv.APIClient()
	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name := resp.ID

	err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// check that IPC is shared
	// 1. create a file inside container
	_, err = container.Exec(ctx, client, name, []string{"sh", "-c", "printf covfefe > /dev/shm/." + name})
	assert.NilError(t, err)
	// 2. check it's the same on the host
	bytes, err := ioutil.ReadFile("/dev/shm/." + name)
	assert.NilError(t, err)
	assert.Check(t, is.Equal("covfefe", string(bytes)))
	// 3. clean up
	_, err = container.Exec(ctx, client, name, []string{"rm", "-f", "/dev/shm/." + name})
	assert.NilError(t, err)
}

// testDaemonIpcPrivateShareable is a helper function to test "private" and "shareable" daemon default ipc modes.
func testDaemonIpcPrivateShareable(t *testing.T, mustBeShared bool, arg ...string) {
	defer setupTest(t)()

	d := daemon.New(t)
	d.StartWithBusybox(t, arg...)
	defer d.Stop(t)

	c := d.NewClientT(t)

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	ctx := context.Background()

	resp, err := c.ContainerCreate(ctx, &cfg, &containertypes.HostConfig{}, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))

	err = c.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// get major:minor pair for /dev/shm from container's /proc/self/mountinfo
	cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo"
	result, err := container.Exec(ctx, c, resp.ID, []string{"sh", "-c", cmd})
	assert.NilError(t, err)
	mm := result.Combined()
	assert.Check(t, is.Equal(true, regexp.MustCompile("^[0-9]+:[0-9]+$").MatchString(mm)))

	shared, err := testIpcCheckDevExists(mm)
	assert.NilError(t, err)
	t.Logf("[testDaemonIpcPrivateShareable] ipcdev: %v, shared: %v, mustBeShared: %v\n", mm, shared, mustBeShared)
	assert.Check(t, is.Equal(shared, mustBeShared))
}

// TestDaemonIpcModeShareable checks that --default-ipc-mode shareable works as intended.
func TestDaemonIpcModeShareable(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcPrivateShareable(t, true, "--default-ipc-mode", "shareable")
}

// TestDaemonIpcModePrivate checks that --default-ipc-mode private works as intended.
func TestDaemonIpcModePrivate(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcPrivateShareable(t, false, "--default-ipc-mode", "private")
}

// used to check if an IpcMode given in config works as intended
func testDaemonIpcFromConfig(t *testing.T, mode string, mustExist bool) {
	config := `{"default-ipc-mode": "` + mode + `"}`
	file := fs.NewFile(t, "test-daemon-ipc-config", fs.WithContent(config))
	defer file.Remove()

	testDaemonIpcPrivateShareable(t, mustExist, "--config-file", file.Path())
}

// TestDaemonIpcModePrivateFromConfig checks that "default-ipc-mode: private" config works as intended.
func TestDaemonIpcModePrivateFromConfig(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcFromConfig(t, "private", false)
}

// TestDaemonIpcModeShareableFromConfig checks that "default-ipc-mode: shareable" config works as intended.
func TestDaemonIpcModeShareableFromConfig(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcFromConfig(t, "shareable", true)
}

// TestIpcModeOlderClient checks that older client gets shareable IPC mode
// by default, even when the daemon default is private.
func TestIpcModeOlderClient(t *testing.T) {
	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "requires a daemon with DefaultIpcMode: private")
	t.Parallel()

	ctx := context.Background()

	// pre-check: default ipc mode in daemon is private
	c := testEnv.APIClient()
	cID := container.Create(t, ctx, c, container.WithAutoRemove)

	inspect, err := c.ContainerInspect(ctx, cID)
	assert.NilError(t, err)
	assert.Check(t, is.Equal(string(inspect.HostConfig.IpcMode), "private"))

	// main check: using older client creates "shareable" container
	c = request.NewAPIClient(t, client.WithVersion("1.39"))
	cID = container.Create(t, ctx, c, container.WithAutoRemove)

	inspect, err = c.ContainerInspect(ctx, cID)
	assert.NilError(t, err)
	assert.Check(t, is.Equal(string(inspect.HostConfig.IpcMode), "shareable"))
}
<commit_msg>TestIpcModeOlderClient: skip if client < 1.40<commit_after>package container // import "github.com/docker/docker/integration/container"

import (
	"bufio"
	"context"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"testing"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/client"
	"github.com/docker/docker/integration/internal/container"
	"github.com/docker/docker/internal/test/daemon"
	"github.com/docker/docker/internal/test/request"
	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
	"gotest.tools/fs"
	"gotest.tools/skip"
)

// testIpcCheckDevExists checks whether a given mount (identified by its
// major:minor pair from /proc/self/mountinfo) exists on the host system.
//
// The format of /proc/self/mountinfo is like:
//
// 29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
//       ^^^^\
//            - this is the minor:major we look for
func testIpcCheckDevExists(mm string) (bool, error) {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return false, err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		fields := strings.Fields(s.Text())
		if len(fields) < 7 {
			continue
		}
		if fields[2] == mm {
			return true, nil
		}
	}

	return false, s.Err()
}

// testIpcNonePrivateShareable is a helper function to test "none",
// "private" and "shareable" modes.
func testIpcNonePrivateShareable(t *testing.T, mode string, mustBeMounted bool, mustBeShared bool) {
	defer setupTest(t)()

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode(mode),
	}
	client := testEnv.APIClient()
	ctx := context.Background()

	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))

	err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// get major:minor pair for /dev/shm from container's /proc/self/mountinfo
	cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo"
	result, err := container.Exec(ctx, client, resp.ID, []string{"sh", "-c", cmd})
	assert.NilError(t, err)
	mm := result.Combined()
	if !mustBeMounted {
		assert.Check(t, is.Equal(mm, ""))
		// no more checks to perform
		return
	}
	assert.Check(t, is.Equal(true, regexp.MustCompile("^[0-9]+:[0-9]+$").MatchString(mm)))

	shared, err := testIpcCheckDevExists(mm)
	assert.NilError(t, err)
	t.Logf("[testIpcPrivateShareable] ipcmode: %v, ipcdev: %v, shared: %v, mustBeShared: %v\n", mode, mm, shared, mustBeShared)
	assert.Check(t, is.Equal(shared, mustBeShared))
}

// TestIpcModeNone checks the container "none" IPC mode
// (--ipc none) works as expected. It makes sure there is no
// /dev/shm mount inside the container.
func TestIpcModeNone(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "none", false, false)
}

// TestAPIIpcModePrivate checks the container private IPC mode
// (--ipc private) works as expected. It gets the minor:major pair
// of /dev/shm mount from the container, and makes sure there is no
// such pair on the host.
func TestIpcModePrivate(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "private", true, false)
}

// TestAPIIpcModeShareable checks the container shareable IPC mode
// (--ipc shareable) works as expected. It gets the minor:major pair
// of /dev/shm mount from the container, and makes sure such pair
// also exists on the host.
func TestIpcModeShareable(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcNonePrivateShareable(t, "shareable", true, true)
}

// testIpcContainer is a helper function to test --ipc container:NNN mode in various scenarios
func testIpcContainer(t *testing.T, donorMode string, mustWork bool) {
	t.Helper()

	defer setupTest(t)()

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode(donorMode),
	}
	ctx := context.Background()
	client := testEnv.APIClient()

	// create and start the "donor" container
	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name1 := resp.ID

	err = client.ContainerStart(ctx, name1, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// create and start the second container
	hostCfg.IpcMode = containertypes.IpcMode("container:" + name1)
	resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name2 := resp.ID

	err = client.ContainerStart(ctx, name2, types.ContainerStartOptions{})
	if !mustWork {
		// start should fail with a specific error
		assert.Check(t, is.ErrorContains(err, "non-shareable IPC"))
		// no more checks to perform here
		return
	}

	// start should succeed
	assert.NilError(t, err)

	// check that IPC is shared
	// 1. create a file in the first container
	_, err = container.Exec(ctx, client, name1, []string{"sh", "-c", "printf covfefe > /dev/shm/bar"})
	assert.NilError(t, err)
	// 2. check it's the same file in the second one
	result, err := container.Exec(ctx, client, name2, []string{"cat", "/dev/shm/bar"})
	assert.NilError(t, err)
	out := result.Combined()
	assert.Check(t, is.Equal(true, regexp.MustCompile("^covfefe$").MatchString(out)))
}

// TestAPIIpcModeShareableAndPrivate checks that
// 1) a container created with --ipc container:ID can use IPC of another shareable container.
// 2) a container created with --ipc container:ID can NOT use IPC of another private container.
func TestAPIIpcModeShareableAndContainer(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testIpcContainer(t, "shareable", true)

	testIpcContainer(t, "private", false)
}

/* TestAPIIpcModeHost checks that a container created with --ipc host
 * can use IPC of the host system.
 */
func TestAPIIpcModeHost(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)
	skip.If(t, testEnv.IsUserNamespace)

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	hostCfg := containertypes.HostConfig{
		IpcMode: containertypes.IpcMode("host"),
	}
	ctx := context.Background()

	client := testEnv.APIClient()
	resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))
	name := resp.ID

	err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// check that IPC is shared
	// 1. create a file inside container
	_, err = container.Exec(ctx, client, name, []string{"sh", "-c", "printf covfefe > /dev/shm/." + name})
	assert.NilError(t, err)
	// 2. check it's the same on the host
	bytes, err := ioutil.ReadFile("/dev/shm/." + name)
	assert.NilError(t, err)
	assert.Check(t, is.Equal("covfefe", string(bytes)))
	// 3. clean up
	_, err = container.Exec(ctx, client, name, []string{"rm", "-f", "/dev/shm/." + name})
	assert.NilError(t, err)
}

// testDaemonIpcPrivateShareable is a helper function to test "private" and "shareable" daemon default ipc modes.
func testDaemonIpcPrivateShareable(t *testing.T, mustBeShared bool, arg ...string) {
	defer setupTest(t)()

	d := daemon.New(t)
	d.StartWithBusybox(t, arg...)
	defer d.Stop(t)

	c := d.NewClientT(t)

	cfg := containertypes.Config{
		Image: "busybox",
		Cmd:   []string{"top"},
	}
	ctx := context.Background()

	resp, err := c.ContainerCreate(ctx, &cfg, &containertypes.HostConfig{}, nil, "")
	assert.NilError(t, err)
	assert.Check(t, is.Equal(len(resp.Warnings), 0))

	err = c.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
	assert.NilError(t, err)

	// get major:minor pair for /dev/shm from container's /proc/self/mountinfo
	cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo"
	result, err := container.Exec(ctx, c, resp.ID, []string{"sh", "-c", cmd})
	assert.NilError(t, err)
	mm := result.Combined()
	assert.Check(t, is.Equal(true, regexp.MustCompile("^[0-9]+:[0-9]+$").MatchString(mm)))

	shared, err := testIpcCheckDevExists(mm)
	assert.NilError(t, err)
	t.Logf("[testDaemonIpcPrivateShareable] ipcdev: %v, shared: %v, mustBeShared: %v\n", mm, shared, mustBeShared)
	assert.Check(t, is.Equal(shared, mustBeShared))
}

// TestDaemonIpcModeShareable checks that --default-ipc-mode shareable works as intended.
func TestDaemonIpcModeShareable(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcPrivateShareable(t, true, "--default-ipc-mode", "shareable")
}

// TestDaemonIpcModePrivate checks that --default-ipc-mode private works as intended.
func TestDaemonIpcModePrivate(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcPrivateShareable(t, false, "--default-ipc-mode", "private")
}

// used to check if an IpcMode given in config works as intended
func testDaemonIpcFromConfig(t *testing.T, mode string, mustExist bool) {
	config := `{"default-ipc-mode": "` + mode + `"}`
	file := fs.NewFile(t, "test-daemon-ipc-config", fs.WithContent(config))
	defer file.Remove()

	testDaemonIpcPrivateShareable(t, mustExist, "--config-file", file.Path())
}

// TestDaemonIpcModePrivateFromConfig checks that "default-ipc-mode: private" config works as intended.
func TestDaemonIpcModePrivateFromConfig(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcFromConfig(t, "private", false)
}

// TestDaemonIpcModeShareableFromConfig checks that "default-ipc-mode: shareable" config works as intended.
func TestDaemonIpcModeShareableFromConfig(t *testing.T) {
	skip.If(t, testEnv.IsRemoteDaemon)

	testDaemonIpcFromConfig(t, "shareable", true)
}

// TestIpcModeOlderClient checks that older client gets shareable IPC mode
// by default, even when the daemon default is private.
func TestIpcModeOlderClient(t *testing.T) {
	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "requires a daemon with DefaultIpcMode: private")
	c := testEnv.APIClient()
	skip.If(t, versions.LessThan(c.ClientVersion(), "1.40"), "requires client API >= 1.40")

	t.Parallel()

	ctx := context.Background()

	// pre-check: default ipc mode in daemon is private
	cID := container.Create(t, ctx, c, container.WithAutoRemove)

	inspect, err := c.ContainerInspect(ctx, cID)
	assert.NilError(t, err)
	assert.Check(t, is.Equal(string(inspect.HostConfig.IpcMode), "private"))

	// main check: using older client creates "shareable" container
	c = request.NewAPIClient(t, client.WithVersion("1.39"))
	cID = container.Create(t, ctx, c, container.WithAutoRemove)

	inspect, err = c.ContainerInspect(ctx, cID)
	assert.NilError(t, err)
	assert.Check(t, is.Equal(string(inspect.HostConfig.IpcMode), "shareable"))
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail_test

import (
	"fmt"
	"os"
	"path"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestLogGlobMatchesAfterStartupWithPollInterval(t *testing.T) {
	for _, pollInterval := range []time.Duration{0, 250 * time.Millisecond} {
		t.Run(fmt.Sprintf("%s", pollInterval), func(t *testing.T) {
			tmpDir, rmTmpDir := testutil.TestTempDir(t)
			defer rmTmpDir()

			logDir := path.Join(tmpDir, "logs")
			progDir := path.Join(tmpDir, "progs")
			err := os.Mkdir(logDir, 0700)
			if err != nil {
				t.Fatal(err)
			}
			err = os.Mkdir(progDir, 0700)
			if err != nil {
				t.Fatal(err)
			}
			defer testutil.TestChdir(t, logDir)()

			m, stopM := mtail.TestStartServer(t, pollInterval, false, mtail.ProgramPath(progDir), mtail.LogPathPatterns(logDir+"/log*"))
			defer stopM()

			startLogCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
			startLineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

			{
				logFile := path.Join(logDir, "log")
				f := testutil.TestOpenFile(t, logFile)
				n, err := f.WriteString("line 1\n")
				if err != nil {
					t.Fatal(err)
				}
				glog.Infof("Wrote %d bytes", n)
				time.Sleep(time.Second)

				logCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
				lineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

				if logCount.(float64)-startLogCount.(float64) != 1. {
					t.Errorf("Unexpected log count: got %g, want 1", logCount.(float64)-startLogCount.(float64))
				}
				if lineCount.(float64)-startLineCount.(float64) != 1. {
					t.Errorf("Unexpected line count: got %g, want 1", lineCount.(float64)-startLineCount.(float64))
				}
				time.Sleep(time.Second)
			}
			{

				logFile := path.Join(logDir, "log1")
				f := testutil.TestOpenFile(t, logFile)
				n, err := f.WriteString("line 1\n")
				if err != nil {
					t.Fatal(err)
				}
				glog.Infof("Wrote %d bytes", n)
				time.Sleep(time.Second)

				logCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
				lineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

				if logCount.(float64)-startLogCount.(float64) != 2. {
					t.Errorf("Unexpected log count: got %g, want 2", logCount.(float64)-startLogCount.(float64))
				}
				if lineCount.(float64)-startLineCount.(float64) != 2. {
					t.Errorf("Unexpected line count: got %g, want 2", lineCount.(float64)-startLineCount.(float64))
				}
				time.Sleep(time.Second)
			}
		})
	}
}
<commit_msg>Refactor test to use testutil.<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail_test

import (
	"fmt"
	"os"
	"path"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestLogGlobMatchesAfterStartupWithPollInterval(t *testing.T) {
	for _, pollInterval := range []time.Duration{0, 250 * time.Millisecond} {
		t.Run(fmt.Sprintf("%s", pollInterval), func(t *testing.T) {
			tmpDir, rmTmpDir := testutil.TestTempDir(t)
			defer rmTmpDir()

			logDir := path.Join(tmpDir, "logs")
			progDir := path.Join(tmpDir, "progs")
			testutil.FatalIfErr(t, os.Mkdir(logDir, 0700))
			testutil.FatalIfErr(t, os.Mkdir(progDir, 0700))
			defer testutil.TestChdir(t, logDir)()

			m, stopM := mtail.TestStartServer(t, pollInterval, false, mtail.ProgramPath(progDir), mtail.LogPathPatterns(logDir+"/log*"))
			defer stopM()

			startLogCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
			startLineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

			{
				logFile := path.Join(logDir, "log")
				f := testutil.TestOpenFile(t, logFile)
				n, err := f.WriteString("line 1\n")
				testutil.FatalIfErr(t, err)
				glog.Infof("Wrote %d bytes", n)
				time.Sleep(time.Second)

				logCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
				lineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

				if logCount.(float64)-startLogCount.(float64) != 1. {
					t.Errorf("Unexpected log count: got %g, want 1", logCount.(float64)-startLogCount.(float64))
				}
				if lineCount.(float64)-startLineCount.(float64) != 1. {
					t.Errorf("Unexpected line count: got %g, want 1", lineCount.(float64)-startLineCount.(float64))
				}
				time.Sleep(time.Second)
			}
			{

				logFile := path.Join(logDir, "log1")
				f := testutil.TestOpenFile(t, logFile)
				n, err := f.WriteString("line 1\n")
				testutil.FatalIfErr(t, err)
				glog.Infof("Wrote %d bytes", n)
				time.Sleep(time.Second)

				logCount := mtail.TestGetMetric(t, m.Addr(), "log_count")
				lineCount := mtail.TestGetMetric(t, m.Addr(), "line_count")

				if logCount.(float64)-startLogCount.(float64) != 2. {
					t.Errorf("Unexpected log count: got %g, want 2", logCount.(float64)-startLogCount.(float64))
				}
				if lineCount.(float64)-startLineCount.(float64) != 2. {
					t.Errorf("Unexpected line count: got %g, want 2", lineCount.(float64)-startLineCount.(float64))
				}
				time.Sleep(time.Second)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"cred-alert/inflator"
	"cred-alert/kolsch"
	"cred-alert/mimetype"
	"cred-alert/scanners"
	"cred-alert/scanners/diffscanner"
	"cred-alert/scanners/dirscanner"
	"cred-alert/scanners/filescanner"
	"cred-alert/sniff"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"code.cloudfoundry.org/lager"

	"github.com/jessevdk/go-flags"
	"github.com/mgutz/ansi"
)

type Opts struct {
	File string `short:"f" long:"file" description:"the file to scan" value-name:"FILE"`
	Diff bool   `long:"diff" description:"content to be scanned is a git diff"`
}

var red = ansi.ColorFunc("red+b")
var green = ansi.ColorFunc("green+b")

func main() {
	var opts Opts

	_, err := flags.ParseArgs(&opts, os.Args)
	if err != nil {
		os.Exit(1)
	}

	logger := kolsch.NewLogger()
	sniffer := sniff.NewDefaultSniffer()
	inflate := inflator.New()
	defer inflate.Close()

	var credsFound int
	handler := func(logger lager.Logger, line scanners.Line) error {
		credsFound++
		fmt.Printf("%s %s:%d\n", red("[CRED]"), line.Path, line.LineNumber)

		return nil
	}

	if opts.File != "" {
		fh, err := os.Open(opts.File)
		if err != nil {
			log.Fatalln(err.Error())
		}

		br := bufio.NewReader(fh)
		mime, isArchive := mimetype.IsArchive(logger, br)
		if isArchive {
			inflateDir, err := ioutil.TempDir("", "cred-alert-cli")
			if err != nil {
				log.Fatalln(err.Error())
			}
			defer os.RemoveAll(inflateDir)

			violationsDir, err := ioutil.TempDir("", "cred-alert-cli-violations")
			if err != nil {
				log.Fatalln(err.Error())
			}

			archiveViolationHandler := func(logger lager.Logger, line scanners.Line) error {
				credsFound++
				relPath, err := filepath.Rel(inflateDir, line.Path)
				if err != nil {
					return err
				}

				destPath := filepath.Join(violationsDir, relPath)
				err = os.MkdirAll(filepath.Dir(destPath), os.ModePerm)
				if err != nil {
					return err
				}

				err = persistFile(line.Path, destPath)
				if err != nil {
					return err
				}

				fmt.Printf("%s %s:%d\n", red("[CRED]"), destPath, line.LineNumber)

				return nil
			}

			inflateStart := time.Now()
			fmt.Printf("Inflating archive... ", inflateDir)
			err = inflate.Inflate(logger, opts.File, inflateDir)
			if err != nil {
				fmt.Printf("%s\n", red("FAILED"))
				log.Fatalln(err.Error())
			}
			fmt.Printf("%s (%s)\n", green("DONE"), time.Since(inflateStart))

			scanStart := time.Now()
			dirScanner := dirscanner.New(archiveViolationHandler, sniffer)
			err = dirScanner.Scan(logger, inflateDir)
			if err != nil {
				log.Fatalln(err.Error())
			}

			fmt.Println()
			fmt.Println("Scan complete!")
			fmt.Println()
			fmt.Println("Time taken:", time.Since(scanStart))
			fmt.Println("Credentials found:", credsFound)
			fmt.Println()
			fmt.Println("Any archive inflation errors can be found in: ", inflate.LogPath())
		} else {
			if strings.HasPrefix(mime, "text") {
				scanFile(logger, handler, sniffer, br, opts.File)
			}
		}
	} else if opts.Diff {
		handleDiff(logger, handler, opts)

	} else {
		scanFile(logger, handler, sniffer, os.Stdin, "STDIN")
	}

	if credsFound > 0 {
		os.Exit(3)
	}
}

func persistFile(srcPath, destPath string) error {
	destFile, err := os.Create(destPath)
	if err != nil {
		return err
	}
	defer destFile.Close()

	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	_, err = io.Copy(destFile, srcFile)
	return err
}

func scanFile(
	logger lager.Logger,
	handler sniff.ViolationHandlerFunc,
	sniffer sniff.Sniffer,
	f io.Reader,
	name string,
) {
	scanner := filescanner.New(f, name)
	sniffer.Sniff(logger, scanner, handler)
}

func handleDiff(logger lager.Logger, handler sniff.ViolationHandlerFunc, opts Opts) {
	logger.Session("handle-diff")
	scanner := diffscanner.NewDiffScanner(os.Stdin)
	sniffer := sniff.NewDefaultSniffer()

	sniffer.Sniff(logger, scanner, handler)
}
<commit_msg>Fix inflating archive message<commit_after>package main

import (
	"bufio"
	"cred-alert/inflator"
	"cred-alert/kolsch"
	"cred-alert/mimetype"
	"cred-alert/scanners"
	"cred-alert/scanners/diffscanner"
	"cred-alert/scanners/dirscanner"
	"cred-alert/scanners/filescanner"
	"cred-alert/sniff"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"code.cloudfoundry.org/lager"

	"github.com/jessevdk/go-flags"
	"github.com/mgutz/ansi"
)

type Opts struct {
	File string `short:"f" long:"file" description:"the file to scan" value-name:"FILE"`
	Diff bool   `long:"diff" description:"content to be scanned is a git diff"`
}

var red = ansi.ColorFunc("red+b")
var green = ansi.ColorFunc("green+b")

func main() {
	var opts Opts

	_, err := flags.ParseArgs(&opts, os.Args)
	if err != nil {
		os.Exit(1)
	}

	logger := kolsch.NewLogger()
	sniffer := sniff.NewDefaultSniffer()
	inflate := inflator.New()
	defer inflate.Close()

	var credsFound int
	handler := func(logger lager.Logger, line scanners.Line) error {
		credsFound++
		fmt.Printf("%s %s:%d\n", red("[CRED]"), line.Path, line.LineNumber)

		return nil
	}

	if opts.File != "" {
		fh, err := os.Open(opts.File)
		if err != nil {
			log.Fatalln(err.Error())
		}

		br := bufio.NewReader(fh)
		mime, isArchive := mimetype.IsArchive(logger, br)
		if isArchive {
			inflateDir, err := ioutil.TempDir("", "cred-alert-cli")
			if err != nil {
				log.Fatalln(err.Error())
			}
			defer os.RemoveAll(inflateDir)

			violationsDir, err := ioutil.TempDir("", "cred-alert-cli-violations")
			if err != nil {
				log.Fatalln(err.Error())
			}

			archiveViolationHandler := func(logger lager.Logger, line scanners.Line) error {
				credsFound++
				relPath, err := filepath.Rel(inflateDir, line.Path)
				if err != nil {
					return err
				}

				destPath := filepath.Join(violationsDir, relPath)
				err = os.MkdirAll(filepath.Dir(destPath), os.ModePerm)
				if err != nil {
					return err
				}

				err = persistFile(line.Path, destPath)
				if err != nil {
					return err
				}

				fmt.Printf("%s %s:%d\n", red("[CRED]"), destPath, line.LineNumber)

				return nil
			}

			inflateStart := time.Now()
			fmt.Printf("Inflating archive into %s\n", inflateDir)
			err = inflate.Inflate(logger, opts.File, inflateDir)
			if err != nil {
				fmt.Printf("%s\n", red("FAILED"))
				log.Fatalln(err.Error())
			}
			fmt.Printf("%s (%s)\n", green("DONE"), time.Since(inflateStart))

			scanStart := time.Now()
			dirScanner := dirscanner.New(archiveViolationHandler, sniffer)
			err = dirScanner.Scan(logger, inflateDir)
			if err != nil {
				log.Fatalln(err.Error())
			}

			fmt.Println()
			fmt.Println("Scan complete!")
			fmt.Println()
			fmt.Println("Time taken:", time.Since(scanStart))
			fmt.Println("Credentials found:", credsFound)
			fmt.Println()
			fmt.Println("Any archive inflation errors can be found in: ", inflate.LogPath())
		} else {
			if strings.HasPrefix(mime, "text") {
				scanFile(logger, handler, sniffer, br, opts.File)
			}
		}
	} else if opts.Diff {
		handleDiff(logger, handler, opts)

	} else {
		scanFile(logger, handler, sniffer, os.Stdin, "STDIN")
	}

	if credsFound > 0 {
		os.Exit(3)
	}
}

func persistFile(srcPath, destPath string) error {
	destFile, err := os.Create(destPath)
	if err != nil {
		return err
	}
	defer destFile.Close()

	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	_, err = io.Copy(destFile, srcFile)
	return err
}

func scanFile(
	logger lager.Logger,
	handler sniff.ViolationHandlerFunc,
	sniffer sniff.Sniffer,
	f io.Reader,
	name string,
) {
	scanner := filescanner.New(f, name)
	sniffer.Sniff(logger, scanner, handler)
}

func handleDiff(logger lager.Logger, handler sniff.ViolationHandlerFunc, opts Opts) {
	logger.Session("handle-diff")
	scanner := diffscanner.NewDiffScanner(os.Stdin)
	sniffer := sniff.NewDefaultSniffer()

	sniffer.Sniff(logger, scanner, handler)
}
<|endoftext|>